diff --git a/.packit.yaml b/.packit.yaml new file mode 100644 index 0000000..de6db74 --- /dev/null +++ b/.packit.yaml @@ -0,0 +1,11 @@ +jobs: +- job: copr_build + metadata: + targets: &id001 [centos-stream-x86_64] + trigger: pull_request +- job: tests + metadata: + targets: *id001 + trigger: pull_request +specfile_path: SPECS/libselinux.spec +upstream_ref: c8-source-git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d386268 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +This library (libselinux) is public domain software, i.e. not copyrighted. + +Warranty Exclusion +------------------ +You agree that this software is a +non-commercially developed program that may contain "bugs" (as that +term is used in the industry) and that it may not function as intended. +The software is licensed "as is". NSA makes no, and hereby expressly +disclaims all, warranties, express, implied, statutory, or otherwise +with respect to the software, including noninfringement and the implied +warranties of merchantability and fitness for a particular purpose. + +Limitation of Liability +----------------------- +In no event will NSA be liable for any damages, including loss of data, +lost profits, cost of cover, or other special, incidental, +consequential, direct or indirect damages arising from the software or +the use thereof, however caused and on any theory of liability. This +limitation will apply even if NSA has been advised of the possibility +of such damage. You acknowledge that this is a reasonable allocation of +risk. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..16531fe --- /dev/null +++ b/Makefile @@ -0,0 +1,69 @@ +SUBDIRS = src include utils man + +PKG_CONFIG ?= pkg-config +DISABLE_SETRANS ?= n +DISABLE_RPM ?= n +ANDROID_HOST ?= n +ifeq ($(ANDROID_HOST),y) + override DISABLE_SETRANS=y + override DISABLE_BOOL=y +endif +ifeq ($(DISABLE_RPM),y) + DISABLE_FLAGS+= -DDISABLE_RPM +endif +ifeq ($(DISABLE_SETRANS),y) + DISABLE_FLAGS+= -DDISABLE_SETRANS +endif +ifeq ($(DISABLE_BOOL),y) + DISABLE_FLAGS+= -DDISABLE_BOOL +endif +export DISABLE_SETRANS DISABLE_RPM DISABLE_FLAGS ANDROID_HOST + +USE_PCRE2 ?= n +ifeq ($(USE_PCRE2),y) + PCRE_MODULE := libpcre2-8 + PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 +else + PCRE_MODULE := libpcre +endif +PCRE_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(PCRE_MODULE)) +PCRE_LDLIBS := $(shell $(PKG_CONFIG) --libs $(PCRE_MODULE)) +export PCRE_MODULE PCRE_CFLAGS PCRE_LDLIBS + +OS := $(shell uname) +export OS + +ifeq ($(shell $(CC) -v 2>&1 | grep "clang"),) +COMPILER := gcc +else +COMPILER := clang +endif +export COMPILER + +all install relabel clean distclean indent: + @for subdir in $(SUBDIRS); do \ + (cd $$subdir && $(MAKE) $@) || exit 1; \ + done + +swigify: all + $(MAKE) -C src swigify $@ + +pywrap: + $(MAKE) -C src pywrap $@ + +rubywrap: + $(MAKE) -C src rubywrap $@ + +install-pywrap: + $(MAKE) -C src install-pywrap $@ + +install-rubywrap: + $(MAKE) -C src install-rubywrap $@ + +clean-pywrap: + $(MAKE) -C src clean-pywrap $@ + +clean-rubywrap: + $(MAKE) -C src clean-rubywrap $@ + +test: diff --git a/SPECS/0001-Fix-selinux-man-page-to-refer-seinfo-and-sesearch-to.patch b/SPECS/0001-Fix-selinux-man-page-to-refer-seinfo-and-sesearch-to.patch new file mode 100644 index 0000000..f6343b4 --- /dev/null +++ b/SPECS/0001-Fix-selinux-man-page-to-refer-seinfo-and-sesearch-to.patch @@ -0,0 +1,31 @@ +From f71fc47524bef3c4cd8a412e43d13daebd1c418b Mon Sep 17 00:00:00 2001 +From: Miroslav Grepl +Date: Wed, 16 Jul 2014 08:28:03 +0200 +Subject: [PATCH] Fix selinux man page to refer seinfo and sesearch tools. + +--- + libselinux/man/man8/selinux.8 | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libselinux/man/man8/selinux.8 b/libselinux/man/man8/selinux.8 +index e37aee68..bf23b655 100644 +--- a/libselinux/man/man8/selinux.8 ++++ b/libselinux/man/man8/selinux.8 +@@ -91,11 +91,13 @@ This manual page was written by Dan Walsh . + .BR sepolicy (8), + .BR system-config-selinux (8), + .BR togglesebool (8), +-.BR restorecon (8), + .BR fixfiles (8), ++.BR restorecon (8), + .BR setfiles (8), + .BR semanage (8), + .BR sepolicy (8) ++.BR seinfo (8), ++.BR sesearch (8) + + Every confined service on the system has a man page in the following format: + .br +-- +2.21.0 + diff --git a/SPECS/0002-Verify-context-input-to-funtions-to-make-sure-the-co.patch b/SPECS/0002-Verify-context-input-to-funtions-to-make-sure-the-co.patch new file mode 100644 index 0000000..24f28e6 --- /dev/null +++ b/SPECS/0002-Verify-context-input-to-funtions-to-make-sure-the-co.patch @@ -0,0 +1,214 @@ +From ad3d3a0bf819f5895a6884357c2d0e18ea1ef314 Mon Sep 17 00:00:00 2001 +From: Dan Walsh +Date: Mon, 23 Dec 2013 09:50:54 -0500 +Subject: [PATCH] Verify context input to funtions to make sure the context + field is not null. + +Return errno EINVAL, to prevent segfault. + +Rejected by upstream https://marc.info/?l=selinux&m=145036088424584&w=2 + +FIXME: use __attribute__(nonnull (arg-index, ...)) +--- + libselinux/src/avc_sidtab.c | 5 +++++ + libselinux/src/canonicalize_context.c | 5 +++++ + libselinux/src/check_context.c | 5 +++++ + libselinux/src/compute_av.c | 5 +++++ + libselinux/src/compute_create.c | 5 +++++ + libselinux/src/compute_member.c | 5 +++++ + libselinux/src/compute_relabel.c | 5 +++++ + libselinux/src/compute_user.c | 5 +++++ + libselinux/src/fsetfilecon.c | 8 ++++++-- + libselinux/src/lsetfilecon.c | 9 +++++++-- + libselinux/src/setfilecon.c | 8 ++++++-- + 11 files changed, 59 insertions(+), 6 deletions(-) + +diff --git a/libselinux/src/avc_sidtab.c b/libselinux/src/avc_sidtab.c +index 9669264d..c7754305 100644 +--- a/libselinux/src/avc_sidtab.c ++++ b/libselinux/src/avc_sidtab.c +@@ -81,6 +81,11 @@ sidtab_context_to_sid(struct sidtab *s, + int hvalue, rc = 0; + struct sidtab_node *cur; + ++ if (! ctx) { ++ errno=EINVAL; ++ return -1; ++ } ++ + *sid = NULL; + hvalue = sidtab_hash(ctx); + +diff --git a/libselinux/src/canonicalize_context.c b/libselinux/src/canonicalize_context.c +index ba4c9a2c..c8158725 100644 +--- a/libselinux/src/canonicalize_context.c ++++ b/libselinux/src/canonicalize_context.c +@@ -17,6 +17,11 @@ int security_canonicalize_context_raw(const char * con, + size_t size; + int fd, ret; + ++ if (! con) { ++ errno=EINVAL; ++ return -1; ++ } ++ + if (!selinux_mnt) { + errno = ENOENT; + return -1; +diff --git a/libselinux/src/check_context.c b/libselinux/src/check_context.c +index 8a7997f0..5be84348 100644 +--- a/libselinux/src/check_context.c ++++ b/libselinux/src/check_context.c +@@ -14,6 +14,11 @@ int security_check_context_raw(const char * con) + char path[PATH_MAX]; + int fd, ret; + ++ if (! con) { ++ errno=EINVAL; ++ return -1; ++ } ++ + if (!selinux_mnt) { + errno = ENOENT; + return -1; +diff --git a/libselinux/src/compute_av.c b/libselinux/src/compute_av.c +index a47cffe9..6d285a2e 100644 +--- a/libselinux/src/compute_av.c ++++ b/libselinux/src/compute_av.c +@@ -27,6 +27,11 @@ int security_compute_av_flags_raw(const char * scon, + return -1; + } + ++ if ((! scon) || (! tcon)) { ++ errno=EINVAL; ++ return -1; ++ } ++ + snprintf(path, sizeof path, "%s/access", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/src/compute_create.c b/libselinux/src/compute_create.c +index 0975aeac..3e6a48c1 100644 +--- a/libselinux/src/compute_create.c ++++ b/libselinux/src/compute_create.c +@@ -64,6 +64,11 @@ int security_compute_create_name_raw(const char * scon, + return -1; + } + ++ if ((! scon) || (! tcon)) { ++ errno=EINVAL; ++ return -1; ++ } ++ + snprintf(path, sizeof path, "%s/create", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/src/compute_member.c b/libselinux/src/compute_member.c +index 4e2d221e..d1dd9772 100644 +--- a/libselinux/src/compute_member.c ++++ b/libselinux/src/compute_member.c +@@ -25,6 +25,11 @@ int security_compute_member_raw(const char * scon, + return -1; + } + ++ if ((! scon) || (! tcon)) { ++ errno=EINVAL; ++ return -1; ++ } ++ + snprintf(path, sizeof path, "%s/member", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/src/compute_relabel.c b/libselinux/src/compute_relabel.c +index 49f77ef3..c3db7c0a 100644 +--- a/libselinux/src/compute_relabel.c ++++ b/libselinux/src/compute_relabel.c +@@ -25,6 +25,11 @@ int security_compute_relabel_raw(const char * scon, + return -1; + } + ++ if ((! scon) || (! tcon)) { ++ errno=EINVAL; ++ return -1; ++ } ++ + snprintf(path, sizeof path, "%s/relabel", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/src/compute_user.c b/libselinux/src/compute_user.c +index 7b881215..401fd107 100644 +--- a/libselinux/src/compute_user.c ++++ b/libselinux/src/compute_user.c +@@ -24,6 +24,11 @@ int security_compute_user_raw(const char * scon, + return -1; + } + ++ if (! scon) { ++ errno=EINVAL; ++ return -1; ++ } ++ + snprintf(path, sizeof path, "%s/user", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c +index 52707d05..0cbe12d8 100644 +--- a/libselinux/src/fsetfilecon.c ++++ b/libselinux/src/fsetfilecon.c +@@ -9,8 +9,12 @@ + + int fsetfilecon_raw(int fd, const char * context) + { +- int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, +- 0); ++ int rc; ++ if (! context) { ++ errno=EINVAL; ++ return -1; ++ } ++ rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; +diff --git a/libselinux/src/lsetfilecon.c b/libselinux/src/lsetfilecon.c +index 1d3b28a1..ea6d70b7 100644 +--- a/libselinux/src/lsetfilecon.c ++++ b/libselinux/src/lsetfilecon.c +@@ -9,8 +9,13 @@ + + int lsetfilecon_raw(const char *path, const char * context) + { +- int rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, +- 0); ++ int rc; ++ if (! context) { ++ errno=EINVAL; ++ return -1; ++ } ++ ++ rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; +diff --git a/libselinux/src/setfilecon.c b/libselinux/src/setfilecon.c +index d05969c6..3f0200e8 100644 +--- a/libselinux/src/setfilecon.c ++++ b/libselinux/src/setfilecon.c +@@ -9,8 +9,12 @@ + + int setfilecon_raw(const char *path, const char * context) + { +- int rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, +- 0); ++ int rc; ++ if (! context) { ++ errno=EINVAL; ++ return -1; ++ } ++ rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; +-- +2.21.0 + diff --git a/SPECS/0003-libselinux-Allow-to-override-OVERRIDE_GETTID-from-co.patch b/SPECS/0003-libselinux-Allow-to-override-OVERRIDE_GETTID-from-co.patch new file mode 100644 index 0000000..9a11fa7 --- /dev/null +++ b/SPECS/0003-libselinux-Allow-to-override-OVERRIDE_GETTID-from-co.patch @@ -0,0 +1,39 @@ +From a6e839be2c5a77c22a8c72cad001e3f87eaedf2e Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Mon, 11 Mar 2019 15:26:43 +0100 +Subject: [PATCH] libselinux: Allow to override OVERRIDE_GETTID from command + line + +$ make CFLAGS="$CFLAGS -DOVERRIDE_GETTID=0" ... + +Drop this as soon as glibc-2.30 will become real 2.30 version, see +https://bugzilla.redhat.com/show_bug.cgi?id=1685594 + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/procattr.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c +index c6799ef2..cbb6824e 100644 +--- a/libselinux/src/procattr.c ++++ b/libselinux/src/procattr.c +@@ -24,6 +24,7 @@ static __thread char destructor_initialized; + + /* Bionic and glibc >= 2.30 declare gettid() system call wrapper in unistd.h and + * has a definition for it */ ++#ifndef OVERRIDE_GETTID + #ifdef __BIONIC__ + #define OVERRIDE_GETTID 0 + #elif !defined(__GLIBC_PREREQ) +@@ -33,6 +34,7 @@ static __thread char destructor_initialized; + #else + #define OVERRIDE_GETTID 0 + #endif ++#endif + + #if OVERRIDE_GETTID + static pid_t gettid(void) +-- +2.21.0 + diff --git a/SPECS/0004-Bring-some-old-permission-and-flask-constants-back-t.patch b/SPECS/0004-Bring-some-old-permission-and-flask-constants-back-t.patch new file mode 100644 index 0000000..f238dd0 --- /dev/null +++ b/SPECS/0004-Bring-some-old-permission-and-flask-constants-back-t.patch @@ -0,0 +1,55 @@ +From be420729fbf4adc8b32ca3722fa6ca46bb51413d Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Wed, 27 Feb 2019 09:37:17 +0100 +Subject: [PATCH] Bring some old permission and flask constants back to Python + bindings + +--- + libselinux/src/selinuxswig.i | 4 ++++ + libselinux/src/selinuxswig_python.i | 3 ++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libselinux/src/selinuxswig.i b/libselinux/src/selinuxswig.i +index dbdb4c3d..9c5b9263 100644 +--- a/libselinux/src/selinuxswig.i ++++ b/libselinux/src/selinuxswig.i +@@ -5,7 +5,9 @@ + %module selinux + %{ + #include "../include/selinux/avc.h" ++ #include "../include/selinux/av_permissions.h" + #include "../include/selinux/context.h" ++ #include "../include/selinux/flask.h" + #include "../include/selinux/get_context_list.h" + #include "../include/selinux/get_default_type.h" + #include "../include/selinux/label.h" +@@ -58,7 +60,9 @@ + %ignore avc_netlink_check_nb; + + %include "../include/selinux/avc.h" ++%include "../include/selinux/av_permissions.h" + %include "../include/selinux/context.h" ++%include "../include/selinux/flask.h" + %include "../include/selinux/get_context_list.h" + %include "../include/selinux/get_default_type.h" + %include "../include/selinux/label.h" +diff --git a/libselinux/src/selinuxswig_python.i b/libselinux/src/selinuxswig_python.i +index 4c73bf92..6eaab081 100644 +--- a/libselinux/src/selinuxswig_python.i ++++ b/libselinux/src/selinuxswig_python.i +@@ -1,10 +1,11 @@ + /* Author: James Athey + */ + +-/* Never build rpm_execcon interface */ ++/* Never build rpm_execcon interface unless you need to have ACG compatibility + #ifndef DISABLE_RPM + #define DISABLE_RPM + #endif ++*/ + + %module selinux + %{ +-- +2.21.0 + diff --git a/SPECS/0005-libselinux-add-missing-av_permission-values.patch b/SPECS/0005-libselinux-add-missing-av_permission-values.patch new file mode 100644 index 0000000..34acc85 --- /dev/null +++ b/SPECS/0005-libselinux-add-missing-av_permission-values.patch @@ -0,0 +1,32 @@ +From 903c54bf62ffba3c95e22e74c9c43838cd3935a0 Mon Sep 17 00:00:00 2001 +From: Vit Mojzis +Date: Tue, 28 Feb 2017 16:12:43 +0100 +Subject: [PATCH] libselinux: add missing av_permission values + +Add missing av_permission values to av_permissions.h for the sake of +completeness (this interface is obsolete - these values are now +obtained at runtime). + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1025931 + +Signed-off-by: Vit Mojzis +--- + libselinux/include/selinux/av_permissions.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libselinux/include/selinux/av_permissions.h b/libselinux/include/selinux/av_permissions.h +index c1269af9..631f0276 100644 +--- a/libselinux/include/selinux/av_permissions.h ++++ b/libselinux/include/selinux/av_permissions.h +@@ -876,6 +876,8 @@ + #define NSCD__SHMEMHOST 0x00000080UL + #define NSCD__GETSERV 0x00000100UL + #define NSCD__SHMEMSERV 0x00000200UL ++#define NSCD__GETNETGRP 0x00000400UL ++#define NSCD__SHMEMNETGRP 0x00000800UL + #define ASSOCIATION__SENDTO 0x00000001UL + #define ASSOCIATION__RECVFROM 0x00000002UL + #define ASSOCIATION__SETCONTEXT 0x00000004UL +-- +2.21.0 + diff --git a/SPECS/0006-libselinux-Use-Python-distutils-to-install-SELinux-p.patch b/SPECS/0006-libselinux-Use-Python-distutils-to-install-SELinux-p.patch new file mode 100644 index 0000000..b4306d8 --- /dev/null +++ b/SPECS/0006-libselinux-Use-Python-distutils-to-install-SELinux-p.patch @@ -0,0 +1,177 @@ +From 67d490a38a319126f371eaf66a5fc922d7005b1f Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Thu, 16 May 2019 15:01:59 +0200 +Subject: [PATCH] libselinux: Use Python distutils to install SELinux python + bindings + +SWIG-4.0 changed its behavior so that it uses: from . import _selinux which +looks for _selinux module in the same directory as where __init__.py is - +$(PYLIBDIR)/site-packages/selinux. But _selinux module is installed into +$(PYLIBDIR)/site-packages/ since a9604c30a5e2f ("libselinux: Change the location +of _selinux.so"). + +In order to prevent such breakage in future use Python's distutils instead of +building and installing python bindings manually in Makefile. + +Fixes: +>>> import selinux +Traceback (most recent call last): + File "", line 1, in + File "/usr/lib64/python3.7/site-packages/selinux/__init__.py", line 13, in + from . import _selinux +ImportError: cannot import name '_selinux' from 'selinux' (/usr/lib64/python3.7/site-packages/selinux/__init__.py) +>>> + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/.gitignore | 2 +- + libselinux/src/Makefile | 37 ++++++++----------------------------- + libselinux/src/setup.py | 24 ++++++++++++++++++++++++ + 3 files changed, 33 insertions(+), 30 deletions(-) + create mode 100644 libselinux/src/setup.py + +diff --git a/libselinux/src/.gitignore b/libselinux/src/.gitignore +index 4dcc3b3b..428afe5a 100644 +--- a/libselinux/src/.gitignore ++++ b/libselinux/src/.gitignore +@@ -1,4 +1,4 @@ + selinux.py +-selinuxswig_wrap.c ++selinuxswig_python_wrap.c + selinuxswig_python_exception.i + selinuxswig_ruby_wrap.c +diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile +index e9ed0383..826c830c 100644 +--- a/libselinux/src/Makefile ++++ b/libselinux/src/Makefile +@@ -36,7 +36,7 @@ TARGET=libselinux.so + LIBPC=libselinux.pc + SWIGIF= selinuxswig_python.i selinuxswig_python_exception.i + SWIGRUBYIF= selinuxswig_ruby.i +-SWIGCOUT= selinuxswig_wrap.c ++SWIGCOUT= selinuxswig_python_wrap.c + SWIGPYOUT= selinux.py + SWIGRUBYCOUT= selinuxswig_ruby_wrap.c + SWIGLOBJ:= $(patsubst %.c,$(PYPREFIX)%.lo,$(SWIGCOUT)) +@@ -55,7 +55,7 @@ ifeq ($(LIBSEPOLA),) + LDLIBS_LIBSEPOLA := -l:libsepol.a + endif + +-GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) selinuxswig_python_exception.i ++GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) $(SWIGCOUT) selinuxswig_python_exception.i + SRCS= $(filter-out $(GENERATED) audit2why.c, $(sort $(wildcard *.c))) + + MAX_STACK_SIZE=32768 +@@ -125,25 +125,18 @@ DISABLE_FLAGS+= -DNO_ANDROID_BACKEND + SRCS:= $(filter-out label_backends_android.c, $(SRCS)) + endif + +-SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./ $(DISABLE_FLAGS) +- + SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ $(DISABLE_FLAGS) + + all: $(LIBA) $(LIBSO) $(LIBPC) + +-pywrap: all $(SWIGFILES) $(AUDIT2WHYSO) ++pywrap: all selinuxswig_python_exception.i ++ CFLAGS="$(SWIG_CFLAGS)" $(PYTHON) setup.py build_ext -I $(DESTDIR)$(INCLUDEDIR) -L $(DESTDIR)$(LIBDIR) + + rubywrap: all $(SWIGRUBYSO) + +-$(SWIGLOBJ): $(SWIGCOUT) +- $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(PYINC) -fPIC -DSHARED -c -o $@ $< +- + $(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< + +-$(SWIGSO): $(SWIGLOBJ) +- $(CC) $(CFLAGS) $(LDFLAGS) -L. -shared -o $@ $< -lselinux $(PYLIBS) +- + $(SWIGRUBYSO): $(SWIGRUBYLOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -L. -shared -o $@ $^ -lselinux $(RUBYLIBS) + +@@ -161,29 +154,15 @@ $(LIBPC): $(LIBPC).in ../VERSION + selinuxswig_python_exception.i: ../include/selinux/selinux.h + bash -e exception.sh > $@ || (rm -f $@ ; false) + +-$(AUDIT2WHYLOBJ): audit2why.c +- $(CC) $(filter-out -Werror, $(CFLAGS)) $(PYINC) -fPIC -DSHARED -c -o $@ $< +- +-$(AUDIT2WHYSO): $(AUDIT2WHYLOBJ) $(LIBSEPOLA) +- $(CC) $(CFLAGS) $(LDFLAGS) -L. -shared -o $@ $^ -lselinux $(LDLIBS_LIBSEPOLA) $(PYLIBS) -Wl,-soname,audit2why.so,--version-script=audit2why.map,-z,defs +- + %.o: %.c policy.h + $(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $< + + %.lo: %.c policy.h + $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $< + +-$(SWIGCOUT): $(SWIGIF) +- $(SWIG) $< +- +-$(SWIGPYOUT): $(SWIGCOUT) +- + $(SWIGRUBYCOUT): $(SWIGRUBYIF) + $(SWIGRUBY) $< + +-swigify: $(SWIGIF) +- $(SWIG) $< +- + install: all + test -d $(DESTDIR)$(LIBDIR) || install -m 755 -d $(DESTDIR)$(LIBDIR) + install -m 644 $(LIBA) $(DESTDIR)$(LIBDIR) +@@ -194,10 +173,8 @@ install: all + ln -sf --relative $(DESTDIR)$(SHLIBDIR)/$(LIBSO) $(DESTDIR)$(LIBDIR)/$(TARGET) + + install-pywrap: pywrap +- test -d $(DESTDIR)$(PYTHONLIBDIR)/selinux || install -m 755 -d $(DESTDIR)$(PYTHONLIBDIR)/selinux +- install -m 755 $(SWIGSO) $(DESTDIR)$(PYTHONLIBDIR)/_selinux$(PYCEXT) +- install -m 755 $(AUDIT2WHYSO) $(DESTDIR)$(PYTHONLIBDIR)/selinux/audit2why$(PYCEXT) +- install -m 644 $(SWIGPYOUT) $(DESTDIR)$(PYTHONLIBDIR)/selinux/__init__.py ++ $(PYTHON) setup.py install --prefix=$(PREFIX) `test -n "$(DESTDIR)" && echo --root $(DESTDIR)` ++ install -m 644 selinux.py $(DESTDIR)$(PYTHONLIBDIR)/selinux/__init__.py + + install-rubywrap: rubywrap + test -d $(DESTDIR)$(RUBYINSTALL) || install -m 755 -d $(DESTDIR)$(RUBYINSTALL) +@@ -208,6 +185,8 @@ relabel: + + clean-pywrap: + -rm -f $(SWIGLOBJ) $(SWIGSO) $(AUDIT2WHYLOBJ) $(AUDIT2WHYSO) ++ $(PYTHON) setup.py clean ++ -rm -rf build *~ \#* *pyc .#* + + clean-rubywrap: + -rm -f $(SWIGRUBYLOBJ) $(SWIGRUBYSO) +diff --git a/libselinux/src/setup.py b/libselinux/src/setup.py +new file mode 100644 +index 00000000..b12e7869 +--- /dev/null ++++ b/libselinux/src/setup.py +@@ -0,0 +1,24 @@ ++#!/usr/bin/python3 ++ ++from distutils.core import Extension, setup ++ ++setup( ++ name="selinux", ++ version="2.9", ++ description="SELinux python 3 bindings", ++ author="SELinux Project", ++ author_email="selinux@vger.kernel.org", ++ ext_modules=[ ++ Extension('selinux._selinux', ++ sources=['selinuxswig_python.i'], ++ include_dirs=['../include'], ++ library_dirs=['.'], ++ libraries=['selinux']), ++ Extension('selinux.audit2why', ++ sources=['audit2why.c'], ++ include_dirs=['../include'], ++ library_dirs=['.'], ++ libraries=['selinux'], ++ extra_link_args=['-l:libsepol.a']) ++ ], ++) +-- +2.21.0 + diff --git a/SPECS/0007-libselinux-Do-not-use-SWIG_CFLAGS-when-Python-bindin.patch b/SPECS/0007-libselinux-Do-not-use-SWIG_CFLAGS-when-Python-bindin.patch new file mode 100644 index 0000000..a064418 --- /dev/null +++ b/SPECS/0007-libselinux-Do-not-use-SWIG_CFLAGS-when-Python-bindin.patch @@ -0,0 +1,44 @@ +From 6ec8116ee64a25a0c5eb543f0b12ed25f1348c45 Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Thu, 27 Jun 2019 11:17:13 +0200 +Subject: [PATCH] libselinux: Do not use SWIG_CFLAGS when Python bindings are + built + +Fixes: +https://rpmdiff.engineering.redhat.com/run/410372/7/ + +Detecting usr/lib64/python3.6/site-packages/selinux/audit2why.cpython-36m-x86_64-linux-gnu.so with not-hardened warnings ' +Hardened: audit2why.cpython-36m-x86_64-linux-gnu.so: FAIL: Gaps were detected in the annobin coverage. Run with -v to list. +' on x86_64 + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/Makefile | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile +index 826c830c..f64f23a8 100644 +--- a/libselinux/src/Makefile ++++ b/libselinux/src/Makefile +@@ -104,9 +104,6 @@ FTS_LDLIBS ?= + + override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS) + +-SWIG_CFLAGS += -Wno-error -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter \ +- -Wno-shadow -Wno-uninitialized -Wno-missing-prototypes -Wno-missing-declarations +- + RANLIB ?= ranlib + + ARCH := $(patsubst i%86,i386,$(shell uname -m)) +@@ -130,7 +127,7 @@ SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ $(DISABLE_FLAGS) + all: $(LIBA) $(LIBSO) $(LIBPC) + + pywrap: all selinuxswig_python_exception.i +- CFLAGS="$(SWIG_CFLAGS)" $(PYTHON) setup.py build_ext -I $(DESTDIR)$(INCLUDEDIR) -L $(DESTDIR)$(LIBDIR) ++ $(PYTHON) setup.py build_ext -I $(DESTDIR)$(INCLUDEDIR) -L $(DESTDIR)$(LIBDIR) + + rubywrap: all $(SWIGRUBYSO) + +-- +2.21.0 + diff --git a/SPECS/0008-Fix-mcstrans-secolor-examples.patch b/SPECS/0008-Fix-mcstrans-secolor-examples.patch new file mode 100644 index 0000000..d2c91ef --- /dev/null +++ b/SPECS/0008-Fix-mcstrans-secolor-examples.patch @@ -0,0 +1,66 @@ +From 90a4f2b9a5194a2d1ab4c45b7a90bbb6c8099a68 Mon Sep 17 00:00:00 2001 +From: Vit Mojzis +Date: Tue, 2 Jul 2019 14:09:05 +0200 +Subject: [PATCH] Fix mcstrans secolor examples + +According to "check_dominance" function: +Range defined as "s15:c0.c1023" does not dominate any other range than + "s15:c0.c1023" (does not dominate "s15", "s15:c0.c200", etc.). +While range defined as "s15-s15:c0.c1023" dominates all of the above. + +This is either a bug, or "s15:c0.c1023" should not be used in the +examples. + +Signed-off-by: Vit Mojzis +--- + libselinux/man/man5/secolor.conf.5 | 4 ++-- + libselinux/man/ru/man5/secolor.conf.5 | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libselinux/man/man5/secolor.conf.5 b/libselinux/man/man5/secolor.conf.5 +index b834577a..a3bf2da1 100644 +--- a/libselinux/man/man5/secolor.conf.5 ++++ b/libselinux/man/man5/secolor.conf.5 +@@ -123,7 +123,7 @@ range s7\-s7:c0.c1023 = black red + .br + range s9\-s9:c0.c1023 = black orange + .br +-range s15:c0.c1023 = black yellow ++range s15\-s15:c0.c1023 = black yellow + .RE + + .sp +@@ -165,7 +165,7 @@ type xguest_t = black green + .br + user sysadm_u = white black + .br +-range s0:c0.c1023 = black white ++range s0-s0:c0.c1023 = black white + .br + user * = black white + .br +diff --git a/libselinux/man/ru/man5/secolor.conf.5 b/libselinux/man/ru/man5/secolor.conf.5 +index 4c1236ae..bcae80c1 100644 +--- a/libselinux/man/ru/man5/secolor.conf.5 ++++ b/libselinux/man/ru/man5/secolor.conf.5 +@@ -121,7 +121,7 @@ range s7\-s7:c0.c1023 = black red + .br + range s9\-s9:c0.c1023 = black orange + .br +-range s15:c0.c1023 = black yellow ++range s15\-s15:c0.c1023 = black yellow + .RE + + .sp +@@ -163,7 +163,7 @@ type xguest_t = black green + .br + user sysadm_u = white black + .br +-range s0:c0.c1023 = black white ++range s0\-s0:c0.c1023 = black white + .br + user * = black white + .br +-- +2.21.0 + diff --git a/SPECS/0009-libselinux-Eliminate-use-of-security_compute_user.patch b/SPECS/0009-libselinux-Eliminate-use-of-security_compute_user.patch new file mode 100644 index 0000000..68085cf --- /dev/null +++ b/SPECS/0009-libselinux-Eliminate-use-of-security_compute_user.patch @@ -0,0 +1,354 @@ +From bfee1a3131580a7b9d8a7366764b8e78d99a9f1b Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Mon, 17 Feb 2020 21:47:35 +0100 +Subject: [PATCH] libselinux: Eliminate use of security_compute_user() + +get_ordered_context_list() code used to ask the kernel to compute the complete +set of reachable contexts using /sys/fs/selinux/user aka +security_compute_user(). This set can be so huge so that it doesn't fit into a +kernel page and security_compute_user() fails. Even if it doesn't fail, +get_ordered_context_list() throws away the vast majority of the returned +contexts because they don't match anything in +/etc/selinux/targeted/contexts/default_contexts or +/etc/selinux/targeted/contexts/users/ + +get_ordered_context_list() is rewritten to compute set of contexts based on +/etc/selinux/targeted/contexts/users/ and +/etc/selinux/targeted/contexts/default_contexts files and to return only valid +contexts, using security_check_context(), from this set. + +Fixes: https://github.com/SELinuxProject/selinux/issues/28 + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/get_context_list.c | 212 +++++++++++++----------------- + 1 file changed, 93 insertions(+), 119 deletions(-) + +diff --git a/libselinux/src/get_context_list.c b/libselinux/src/get_context_list.c +index 689e4658..26d7b3b9 100644 +--- a/libselinux/src/get_context_list.c ++++ b/libselinux/src/get_context_list.c +@@ -2,6 +2,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -114,64 +115,41 @@ int get_default_context(const char *user, + return 0; + } + +-static int find_partialcon(char ** list, +- unsigned int nreach, char *part) ++static int is_in_reachable(char **reachable, const char *usercon_str) + { +- const char *conrole, *contype; +- char *partrole, *parttype, *ptr; +- context_t con; +- unsigned int i; ++ if (!reachable) ++ return 0; + +- partrole = part; +- ptr = part; +- while (*ptr && !isspace(*ptr) && *ptr != ':') +- ptr++; +- if (*ptr != ':') +- return -1; +- *ptr++ = 0; +- parttype = ptr; +- while (*ptr && !isspace(*ptr) && *ptr != ':') +- ptr++; +- *ptr = 0; +- +- for (i = 0; i < nreach; i++) { +- con = context_new(list[i]); +- if (!con) +- return -1; +- conrole = context_role_get(con); +- contype = context_type_get(con); +- if (!conrole || !contype) { +- context_free(con); +- return -1; +- } +- if (!strcmp(conrole, partrole) && !strcmp(contype, parttype)) { +- context_free(con); +- return i; ++ for (; *reachable != NULL; reachable++) { ++ if (strcmp(*reachable, usercon_str) == 0) { ++ return 1; + } +- context_free(con); + } +- +- return -1; ++ return 0; + } + +-static int get_context_order(FILE * fp, ++static int get_context_user(FILE * fp, + char * fromcon, +- char ** reachable, +- unsigned int nreach, +- unsigned int *ordering, unsigned int *nordered) ++ const char * user, ++ char ***reachable, ++ unsigned int *nreachable) + { + char *start, *end = NULL; + char *line = NULL; +- size_t line_len = 0; ++ size_t line_len = 0, usercon_len; ++ size_t user_len = strlen(user); + ssize_t len; + int found = 0; +- const char *fromrole, *fromtype; ++ const char *fromrole, *fromtype, *fromlevel; + char *linerole, *linetype; +- unsigned int i; ++ char **new_reachable = NULL; ++ char *usercon_str; + context_t con; ++ context_t usercon; ++ + int rc; + +- errno = -EINVAL; ++ errno = EINVAL; + + /* Extract the role and type of the fromcon for matching. + User identity and MLS range can be variable. */ +@@ -180,6 +158,7 @@ static int get_context_order(FILE * fp, + return -1; + fromrole = context_role_get(con); + fromtype = context_type_get(con); ++ fromlevel = context_range_get(con); + if (!fromrole || !fromtype) { + context_free(con); + return -1; +@@ -243,23 +222,75 @@ static int get_context_order(FILE * fp, + if (*end) + *end++ = 0; + +- /* Check for a match in the reachable list. */ +- rc = find_partialcon(reachable, nreach, start); +- if (rc < 0) { +- /* No match, skip it. */ ++ /* Check whether a new context is valid */ ++ if (SIZE_MAX - user_len < strlen(start) + 2) { ++ fprintf(stderr, "%s: one of partial contexts is too big\n", __FUNCTION__); ++ errno = EINVAL; ++ rc = -1; ++ goto out; ++ } ++ usercon_len = user_len + strlen(start) + 2; ++ usercon_str = malloc(usercon_len); ++ if (!usercon_str) { ++ rc = -1; ++ goto out; ++ } ++ ++ /* set range from fromcon in the new usercon */ ++ snprintf(usercon_str, usercon_len, "%s:%s", user, start); ++ usercon = context_new(usercon_str); ++ if (!usercon) { ++ if (errno != EINVAL) { ++ free(usercon_str); ++ rc = -1; ++ goto out; ++ } ++ fprintf(stderr, ++ "%s: can't create a context from %s, skipping\n", ++ __FUNCTION__, usercon_str); ++ free(usercon_str); + start = end; + continue; + } ++ free(usercon_str); ++ if (context_range_set(usercon, fromlevel) != 0) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ usercon_str = context_str(usercon); ++ if (!usercon_str) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } + +- /* If a match is found and the entry is not already ordered +- (e.g. due to prior match in prior config file), then set +- the ordering for it. */ +- i = rc; +- if (ordering[i] == nreach) +- ordering[i] = (*nordered)++; ++ /* check whether usercon is already in reachable */ ++ if (is_in_reachable(*reachable, usercon_str)) { ++ context_free(usercon); ++ start = end; ++ continue; ++ } ++ if (security_check_context(usercon_str) == 0) { ++ new_reachable = realloc(*reachable, (*nreachable + 2) * sizeof(char *)); ++ if (!new_reachable) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ *reachable = new_reachable; ++ new_reachable[*nreachable] = strdup(usercon_str); ++ if (new_reachable[*nreachable] == NULL) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ new_reachable[*nreachable + 1] = 0; ++ *nreachable += 1; ++ } ++ context_free(usercon); + start = end; + } +- + rc = 0; + + out: +@@ -313,21 +344,6 @@ static int get_failsafe_context(const char *user, char ** newcon) + return 0; + } + +-struct context_order { +- char * con; +- unsigned int order; +-}; +- +-static int order_compare(const void *A, const void *B) +-{ +- const struct context_order *c1 = A, *c2 = B; +- if (c1->order < c2->order) +- return -1; +- else if (c1->order > c2->order) +- return 1; +- return strcmp(c1->con, c2->con); +-} +- + int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, +@@ -395,11 +411,8 @@ int get_ordered_context_list(const char *user, + char *** list) + { + char **reachable = NULL; +- unsigned int *ordering = NULL; +- struct context_order *co = NULL; +- char **ptr; + int rc = 0; +- unsigned int nreach = 0, nordered = 0, freefrom = 0, i; ++ unsigned nreachable = 0, freefrom = 0; + FILE *fp; + char *fname = NULL; + size_t fname_len; +@@ -413,23 +426,6 @@ int get_ordered_context_list(const char *user, + freefrom = 1; + } + +- /* Determine the set of reachable contexts for the user. */ +- rc = security_compute_user(fromcon, user, &reachable); +- if (rc < 0) +- goto failsafe; +- nreach = 0; +- for (ptr = reachable; *ptr; ptr++) +- nreach++; +- if (!nreach) +- goto failsafe; +- +- /* Initialize ordering array. */ +- ordering = malloc(nreach * sizeof(unsigned int)); +- if (!ordering) +- goto failsafe; +- for (i = 0; i < nreach; i++) +- ordering[i] = nreach; +- + /* Determine the ordering to apply from the optional per-user config + and from the global config. */ + fname_len = strlen(user_contexts_path) + strlen(user) + 2; +@@ -440,8 +436,8 @@ int get_ordered_context_list(const char *user, + fp = fopen(fname, "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); +- rc = get_context_order(fp, fromcon, reachable, nreach, ordering, +- &nordered); ++ rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); ++ + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, +@@ -454,8 +450,7 @@ int get_ordered_context_list(const char *user, + fp = fopen(selinux_default_context_path(), "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); +- rc = get_context_order(fp, fromcon, reachable, nreach, ordering, +- &nordered); ++ rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, +@@ -463,40 +458,19 @@ int get_ordered_context_list(const char *user, + __FUNCTION__, selinux_default_context_path()); + /* Fall through */ + } +- rc = 0; + } + +- if (!nordered) ++ if (!nreachable) + goto failsafe; + +- /* Apply the ordering. */ +- co = malloc(nreach * sizeof(struct context_order)); +- if (!co) +- goto failsafe; +- for (i = 0; i < nreach; i++) { +- co[i].con = reachable[i]; +- co[i].order = ordering[i]; +- } +- qsort(co, nreach, sizeof(struct context_order), order_compare); +- for (i = 0; i < nreach; i++) +- reachable[i] = co[i].con; +- free(co); +- +- /* Only report the ordered entries to the caller. */ +- if (nordered <= nreach) { +- for (i = nordered; i < nreach; i++) +- free(reachable[i]); +- reachable[nordered] = NULL; +- rc = nordered; +- } +- + out: +- if (rc > 0) ++ if (nreachable > 0) { + *list = reachable; ++ rc = nreachable; ++ } + else + freeconary(reachable); + +- free(ordering); + if (freefrom) + freecon(fromcon); + +@@ -519,7 +493,7 @@ int get_ordered_context_list(const char *user, + reachable = NULL; + goto out; + } +- rc = 1; /* one context in the list */ ++ nreachable = 1; /* one context in the list */ + goto out; + } + +-- +2.25.4 + diff --git a/SPECS/libselinux-2.9.tar.gz b/SPECS/libselinux-2.9.tar.gz new file mode 100644 index 0000000..801504b Binary files /dev/null and b/SPECS/libselinux-2.9.tar.gz differ diff --git a/SPECS/libselinux.spec b/SPECS/libselinux.spec new file mode 100644 index 0000000..804b5bb --- /dev/null +++ b/SPECS/libselinux.spec @@ -0,0 +1,2762 @@ + +%global with_ruby 1 + +%if 0%{?with_ruby} +%global ruby_inc %(pkg-config --cflags ruby) +%endif + +%define libsepolver 2.9-1 +%define libselinuxrelease 4 + +Summary: SELinux library and simple utilities +Name: libselinux +Version: 2.9 +Release: %{libselinuxrelease}%{?dist} +License: Public Domain +# https://github.com/SELinuxProject/selinux/wiki/Releases +Source0: https://github.com/SELinuxProject/selinux/releases/download/20190315/libselinux-2.9.tar.gz +Source1: selinuxconlist.8 +Source2: selinuxdefcon.8 +Url: https://github.com/SELinuxProject/selinux/wiki +# i=1; for j in 00*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done +Patch0001: 0001-Fix-selinux-man-page-to-refer-seinfo-and-sesearch-to.patch +Patch0002: 0002-Verify-context-input-to-funtions-to-make-sure-the-co.patch +Patch0003: 0003-libselinux-Allow-to-override-OVERRIDE_GETTID-from-co.patch +Patch0004: 0004-Bring-some-old-permission-and-flask-constants-back-t.patch +Patch0005: 0005-libselinux-add-missing-av_permission-values.patch +Patch0006: 0006-libselinux-Use-Python-distutils-to-install-SELinux-p.patch +Patch0007: 0007-libselinux-Do-not-use-SWIG_CFLAGS-when-Python-bindin.patch +Patch0008: 0008-Fix-mcstrans-secolor-examples.patch +Patch0009: 0009-libselinux-Eliminate-use-of-security_compute_user.patch + +BuildRequires: gcc +%if 0%{?with_ruby} +BuildRequires: ruby-devel ruby libsepol-static >= %{libsepolver} swig pcre2-devel xz-devel +%else +BuildRequires: libsepol-static >= %{libsepolver} swig pcre2-devel xz-devel +%endif +BuildRequires: python3 python3-devel +%if 0%{?with_python2} +BuildRequires: python2 python2-devel +%endif +BuildRequires: systemd +Requires: libsepol%{?_isa} >= %{libsepolver} pcre2 +Conflicts: filesystem < 3, selinux-policy-base < 3.13.1-138 + +%description +Security-enhanced Linux is a feature of the Linux® kernel and a number +of utilities with enhanced security functionality designed to add +mandatory access controls to Linux. The Security-enhanced Linux +kernel contains new architectural components originally developed to +improve the security of the Flask operating system. These +architectural components provide general support for the enforcement +of many kinds of mandatory access control policies, including those +based on the concepts of Type Enforcement®, Role-based Access +Control, and Multi-level Security. + +libselinux provides an API for SELinux applications to get and set +process and file security contexts and to obtain security policy +decisions. Required for any applications that use the SELinux API. + +%package utils +Summary: SELinux libselinux utilities +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description utils +The libselinux-utils package contains the utilities + +%if 0%{?with_python2} +%package -n libselinux-python +%{?python_provide:%python_provide python2-libselinux} +Provides: python2-%{name} = %{version}-%{release} +Provides: python2-%{name}%{?_isa} = %{version}-%{release} +Obsoletes: %{name}-python < %{version}-%{release} +Summary: SELinux python bindings for libselinux +Requires: %{name}%{?_isa} >= %{version}-%{libselinuxrelease} + +%description -n libselinux-python +The libselinux-python package contains the python bindings for developing +SELinux applications. +%endif + +%package -n python3-libselinux +Summary: SELinux python 3 bindings for libselinux +Requires: %{name}%{?_isa} = %{version}-%{release} +%{?python_provide:%python_provide python3-libselinux} +# Remove before F30 +Provides: %{name}-python3 = %{version}-%{release} +Provides: %{name}-python3%{?_isa} = %{version}-%{release} +Obsoletes: %{name}-python3 < %{version}-%{release} + +%description -n python3-libselinux +The libselinux-python3 package contains python 3 bindings for developing +SELinux applications. + +%if 0%{?with_ruby} +%package ruby +Summary: SELinux ruby bindings for libselinux +Requires: %{name}%{?_isa} = %{version}-%{release} +Provides: ruby(selinux) + +%description ruby +The libselinux-ruby package contains the ruby bindings for developing +SELinux applications. +%endif # with_ruby + +%package devel +Summary: Header files and libraries used to build SELinux +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: libsepol-devel%{?_isa} >= %{libsepolver} + +%description devel +The libselinux-devel package contains the libraries and header files +needed for developing SELinux applications. + +%package static +Summary: Static libraries used to build SELinux +Requires: %{name}-devel%{?_isa} = %{version}-%{release} + +%description static +The libselinux-static package contains the static libraries +needed for developing SELinux applications. + +%prep +%autosetup -p 2 -n libselinux-%{version} + +%build +export DISABLE_RPM="n" +export USE_PCRE2="y" + +%set_build_flags + +# To support building the Python wrapper against multiple Python runtimes +# Define a function, for how to perform a "build" of the python wrapper against +# a specific runtime: +BuildPythonWrapper() { + BinaryName=$1 + + # Perform the build from the upstream Makefile: + make \ + PYTHON=$BinaryName \ + LIBDIR="%{_libdir}" %{?_smp_mflags} \ + pywrap +} + +make clean +make LIBDIR="%{_libdir}" %{?_smp_mflags} swigify +make LIBDIR="%{_libdir}" %{?_smp_mflags} all + +%if 0%{?with_python2} +export RHEL_ALLOW_PYTHON2_FOR_BUILD=1 +BuildPythonWrapper %{__python2} +%endif +BuildPythonWrapper %{__python3} + +%if 0%{?with_ruby} +make RUBYINC="%{ruby_inc}" SHLIBDIR="%{_libdir}" LIBDIR="%{_libdir}" LIBSEPOLA="%{_libdir}/libsepol.a" %{?_smp_mflags} rubywrap +%endif + +%install +InstallPythonWrapper() { + BinaryName=$1 + + make \ + PYTHON=$BinaryName \ + LIBDIR="%{_libdir}" %{?_smp_mflags} \ + LIBSEPOLA="%{_libdir}/libsepol.a" \ + pywrap + + make \ + PYTHON=$BinaryName \ + DESTDIR="%{buildroot}" LIBDIR="%{_libdir}" \ + SHLIBDIR="%{_lib}" BINDIR="%{_bindir}" \ + SBINDIR="%{_sbindir}" \ + LIBSEPOLA="%{_libdir}/libsepol.a" \ + install-pywrap +} + +rm -rf %{buildroot} +mkdir -p %{buildroot}%{_tmpfilesdir} +mkdir -p %{buildroot}%{_libdir} +mkdir -p %{buildroot}%{_includedir} +mkdir -p %{buildroot}%{_sbindir} +install -d -m 0755 %{buildroot}%{_rundir}/setrans +echo "d %{_rundir}/setrans 0755 root root" > %{buildroot}%{_tmpfilesdir}/libselinux.conf + +%if 0%{?with_python2} +export RHEL_ALLOW_PYTHON2_FOR_BUILD=1 +InstallPythonWrapper %{__python2} +mv %{buildroot}%{python2_sitearch}/selinux/_selinux.so %{buildroot}%{python2_sitearch}/ +%endif +InstallPythonWrapper %{__python3} +mv %{buildroot}%{python3_sitearch}/selinux/_selinux.*.so %{buildroot}%{python3_sitearch}/ + +%if 0%{?with_ruby} +make DESTDIR="%{buildroot}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" BINDIR="%{_bindir}" SBINDIR="%{_sbindir}" RUBYINSTALL=%{ruby_vendorarchdir} install install-rubywrap +%else +make DESTDIR="%{buildroot}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" BINDIR="%{_bindir}" SBINDIR="%{_sbindir}" install +%endif + +# Nuke the files we don't want to distribute +rm -f %{buildroot}%{_sbindir}/compute_* +rm -f %{buildroot}%{_sbindir}/deftype +rm -f %{buildroot}%{_sbindir}/execcon +rm -f %{buildroot}%{_sbindir}/getenforcemode +rm -f %{buildroot}%{_sbindir}/getfilecon +rm -f %{buildroot}%{_sbindir}/getpidcon +rm -f %{buildroot}%{_sbindir}/mkdircon +rm -f %{buildroot}%{_sbindir}/policyvers +rm -f %{buildroot}%{_sbindir}/setfilecon +rm -f %{buildroot}%{_sbindir}/selinuxconfig +rm -f %{buildroot}%{_sbindir}/selinuxdisable +rm -f %{buildroot}%{_sbindir}/getseuser +rm -f %{buildroot}%{_sbindir}/togglesebool +rm -f %{buildroot}%{_sbindir}/selinux_check_securetty_context +mv %{buildroot}%{_sbindir}/getdefaultcon %{buildroot}%{_sbindir}/selinuxdefcon +mv %{buildroot}%{_sbindir}/getconlist %{buildroot}%{_sbindir}/selinuxconlist +install -d %{buildroot}%{_mandir}/man8/ +install -m 644 %{SOURCE1} %{buildroot}%{_mandir}/man8/ +install -m 644 %{SOURCE2} %{buildroot}%{_mandir}/man8/ +rm -f %{buildroot}%{_mandir}/man8/togglesebool* + +%ldconfig_scriptlets + +%files +%license LICENSE +%{_libdir}/libselinux.so.* +%dir %{_rundir}/setrans/ +%{_tmpfilesdir}/libselinux.conf + +%files utils +%{_sbindir}/avcstat +%{_sbindir}/getenforce +%{_sbindir}/getsebool +%{_sbindir}/matchpathcon +%{_sbindir}/sefcontext_compile +%{_sbindir}/selinuxconlist +%{_sbindir}/selinuxdefcon +%{_sbindir}/selinuxexeccon +%{_sbindir}/selinuxenabled +%{_sbindir}/setenforce +%{_sbindir}/selabel_digest +%{_sbindir}/selabel_lookup +%{_sbindir}/selabel_lookup_best_match +%{_sbindir}/selabel_partial_match +%{_sbindir}/selinux_check_access +%{_mandir}/man5/* +%{_mandir}/man8/* +%{_mandir}/ru/man5/* +%{_mandir}/ru/man8/* + +%files devel +%{_libdir}/libselinux.so +%{_libdir}/pkgconfig/libselinux.pc +%{_includedir}/selinux/ +%{_mandir}/man3/* + +%files static +%{_libdir}/libselinux.a + +%if 0%{?with_python2} +%files -n libselinux-python +%{python2_sitearch}/selinux/ +%{python2_sitearch}/_selinux.so +%{python2_sitearch}/selinux-%{version}-* +%endif + +%files -n python3-libselinux +%{python3_sitearch}/selinux/ +%{python3_sitearch}/_selinux.*.so +%{python3_sitearch}/selinux-%{version}-* + +%if 0%{?with_ruby} +%files ruby +%{ruby_vendorarchdir}/selinux.so +%endif + +%changelog +* Thu Sep 24 2020 Vit Mojzis - 2.9-4 +- Eliminate use of security_compute_user() (#1879368) + +* Fri Nov 08 2019 Vit Mojzis - 2.9-3 +- Fix mcstrans secolor examples in secolor.conf man page (#1770270) + +* Mon Jun 24 2019 Petr Lautrbach - 2.9-2.1 +- Use Python distutils to install SELinux python bindings (#1719771) +- Move sefcontext_compile to -utils package (#1612518) + +* Mon Mar 18 2019 Petr Lautrbach - 2.9-1 +- SELinux userspace 2.9 release + +* Tue Nov 6 2018 Petr Lautrbach - 2.8-6 +- Fix RESOURCE_LEAK coverity scan defects + +* Mon Oct 15 2018 Petr Lautrbach - 2.8-5 +- selinux_restorecon: Skip customized files also without -v +- man pages fixes + +* Mon Oct 1 2018 Petr Lautrbach - 2.8-4 +- Build libselinux-python when %with_python2 macro is set to non-zero value + +* Fri Jun 22 2018 Petr Lautrbach - 2.8-3 +- Build libselinux-ruby (#1581322) + +* Thu Jun 7 2018 Petr Lautrbach - 2.8-2 +- Don't build the Python 2 subpackage (#1567358) + +* Fri May 25 2018 Petr Lautrbach - 2.8-1 +- SELinux userspace 2.8 release + +* Mon May 14 2018 Petr Lautrbach - 2.8-0.rc3.1 +- SELinux userspace 2.8-rc3 release candidate + +* Fri May 4 2018 Petr Lautrbach - 2.8-0.rc2.1 +- SELinux userspace 2.8-rc2 release candidate + +* Mon Apr 23 2018 Petr Lautrbach - 2.8-0.rc1.1 +- SELinux userspace 2.8-rc1 release candidate + +* Mon Apr 23 2018 Petr Lautrbach - 2.7-14 +- Do not build libselinux-ruby + +* Wed Mar 21 2018 Petr Lautrbach - 2.7-13 +- build: Replace PYSITEDIR with PYTHONLIBDIR + +* Tue Mar 13 2018 Petr Lautrbach - 2.7-12 +- Correct manpages regarding removable_context +- build: follow standard semantics for DESTDIR and PREFIX + +* Fri Feb 09 2018 Igor Gnatenko - 2.7-11 +- Escape macros in %%changelog + +* Wed Feb 07 2018 Fedora Release Engineering - 2.7-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Feb 03 2018 Igor Gnatenko - 2.7-9 +- Switch to %%ldconfig_scriptlets + +* Tue Jan 09 2018 Iryna Shcherbina - 2.7-8 +- Update Python 2 dependency declarations to new packaging standards + (See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3) + +* Fri Jan 05 2018 Mamoru TASAKA - 2.7-7 +- F-28: rebuild for ruby25 + +* Wed Nov 22 2017 Petr Lautrbach - 2.7-6 +- Rebuild with libsepol-2.7-3 + +* Fri Oct 20 2017 Petr Lautrbach - 2.7-5 +- Drop golang bindings +- Add support for pcre2 to pkgconfig definition + +* Wed Sep 27 2017 Petr Šabata - 2.7-4 +- Enable the python3 subpackages on EL + +* Sat Aug 19 2017 Zbigniew Jędrzejewski-Szmek - 2.7-3 +- Also add Provides for the old name without %%_isa + +* Thu Aug 10 2017 Zbigniew Jędrzejewski-Szmek - 2.7-2 +- Python 2 binary package renamed to python2-libselinux + See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3 +- Python 3 binary package renamed to python3-libselinux + +* Mon Aug 07 2017 Petr Lautrbach - 2.7-1 +- Update to upstream release 2017-08-04 + +* Thu Aug 03 2017 Fedora Release Engineering - 2.6-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Sat Jul 29 2017 Florian Weimer - 2.6-9 +- Rebuild with binutils fix for ppc64le (#1475636) + +* Fri Jul 28 2017 Petr Lautrbach - 2.6-8 +- Always unmount selinuxfs for SELINUX=disabled + +* Wed Jul 26 2017 Fedora Release Engineering - 2.6-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Apr 28 2017 Petr Lautrbach - 2.6-6 +- Don't finalize mount state in selinux_set_policy_root() +- Follow upstream and rename _selinux.so to _selinux.cpython-36m-x86_64-linux-gnu.so + +* Thu Apr 06 2017 Petr Lautrbach - 2.6-5 +- Fix setfiles progress indicator + +* Wed Mar 22 2017 Petr Lautrbach - 2.6-4 +- Fix segfault in selinux_restorecon_sb() (#1433577) +- Change matchpathcon usage to match with matchpathcon manpage +- Fix a corner case getsebool return value + +* Tue Mar 14 2017 Petr Lautrbach - 2.6-3 +- Fix 'semanage boolean -m' to modify active value + +* Thu Mar 02 2017 Petr Lautrbach - 2.6-2 +- Fix FTBFS - fatal error (#1427902) + +* Sun Feb 12 2017 Petr Lautrbach - 2.6-1 +- Update to upstream release 2016-10-14 + +* Fri Feb 10 2017 Fedora Release Engineering - 2.5-18 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Wed Feb 01 2017 Stephen Gallagher - 2.5-17 +- Add missing %%license macro + +* Fri Jan 13 2017 Vít Ondruch - 2.5-16 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.4 + +* Wed Jan 11 2017 Petr Lautrbach - 2.5-15 +- Rewrite restorecon() python method + +* Fri Dec 09 2016 Charalampos Stratakis - 2.5-14 +- Rebuild for Python 3.6 + +* Tue Nov 22 2016 Petr Lautrbach - 2.5-13 +- Fix pointer handling in realpath_not_final (#1376598) + +* Mon Oct 03 2016 Petr Lautrbach 2.5-12 +- Fix -Wsign-compare warnings +- Drop unused stdio_ext.h header file +- Kill logging check for selinux_enabled() +- Drop usage of _D_ALLOC_NAMLEN +- Add openrc_contexts functions +- Fix redefinition of XATTR_NAME_SELINUX +- Correct error path to always try text +- Clean up process_file() +- Handle NULL pcre study data +- Fix in tree compilation of utils that depend on libsepol + +* Mon Aug 01 2016 Petr Lautrbach 2.5-11 +- Rebuilt with libsepol-2.5-9 + +* Tue Jul 19 2016 Fedora Release Engineering - 2.5-10 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Mon Jun 27 2016 Petr Lautrbach - 2.5-9 +- Clarify is_selinux_mls_enabled() description +- Explain how to free policy type from selinux_getpolicytype() +- Compare absolute pathname in matchpathcon -V +- Add selinux_snapperd_contexts_path() + +* Fri Jun 24 2016 Petr Lautrbach - 2.5-8 +- Move _selinux.so to /usr/lib64/python*/site-packages + +* Thu Jun 23 2016 Petr Lautrbach - 2.5-7 +- Modify audit2why analyze function to use loaded policy +- Sort object files for deterministic linking order +- Respect CC and PKG_CONFIG environment variable +- Avoid mounting /proc outside of selinux_init_load_policy() + +* Fri May 06 2016 Petr Lautrbach - 2.5-6 +- Fix multiple spelling errors + +* Mon May 02 2016 Petr Lautrbach - 2.5-5 +- Rebuilt with libsepol-2.5-5 + +* Fri Apr 29 2016 Petr Lautrbach - 2.5-4 +- Fix typo in sefcontext_compile.8 + +* Fri Apr 08 2016 Petr Lautrbach - 2.5-3 +- Fix location of selinuxfs mount point +- Only mount /proc if necessary +- procattr: return einval for <= 0 pid args +- procattr: return error on invalid pid_t input + +* Sat Feb 27 2016 Petr Lautrbach 2.5-2 +- Use fully versioned arch-specific requires + +* Tue Feb 23 2016 Petr Lautrbach 2.5-1 +- Update to upstream release 2016-02-23 + +* Sun Feb 21 2016 Petr Lautrbach 2.5-0.1.rc1 +- Update to upstream rc1 release 2016-01-07 + +* Thu Feb 04 2016 Fedora Release Engineering - 2.4-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Jan 12 2016 Vít Ondruch - 2.4-7 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.3 + +* Thu Dec 10 2015 Petr Lautrbach - 2.4-6 +- Build libselinux without rpm_execcon() (#1284019) + +* Thu Oct 15 2015 Robert Kuska - 2.4-5 +- Rebuilt for Python3.5 rebuild + +* Wed Sep 30 2015 Petr Lautrbach 2.4-4 +- Flush the class/perm string mapping cache on policy reload (#1264051) +- Fix restorecon when path has no context + +* Wed Sep 02 2015 Petr Lautrbach 2.4-3 +- Simplify procattr cache (#1257157,#1232371) + +* Fri Aug 14 2015 Adam Jackson 2.4-2 +- Export ldflags into the build so hardening works + +* Tue Jul 21 2015 Petr Lautrbach 2.4-1.1 +- Update to 2.4 release + +* Wed Jun 17 2015 Fedora Release Engineering - 2.3-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue May 12 2015 Petr Lautrbach 2.3-10 +- is_selinux_enabled: Add /etc/selinux/config test (#1219045) +- matchpathcon/selabel_file: Fix man pages (#1219718) + +* Thu Apr 23 2015 Petr Lautrbach 2.3-9 +- revert support for policy compressed with xv (#1185266) + +* Tue Apr 21 2015 Petr Lautrbach 2.3-8 +- selinux.py - use os.walk() instead of os.path.walk() (#1195004) +- is_selinux_enabled(): drop no-policy-loaded test (#1195074) +- fix -Wformat errors and remove deprecated mudflap option + +* Mon Mar 16 2015 Than Ngo - 2.3-7 +- bump release and rebuild so that koji-shadow can rebuild it + against new gcc on secondary arch + +* Mon Jan 19 2015 Vít Ondruch - 2.3-6 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.2 + +* Thu Aug 21 2014 Miroslav Grepl - 2.3-5 +- Compiled file context files and the original should have the same permissions from dwalsh@redhat.com +- Add selinux_openssh_contexts_path() to get a path to /contexts/openssh_contexts + +* Sun Aug 17 2014 Fedora Release Engineering - 2.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 2.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Kalev Lember - 2.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* Tue May 6 2014 Dan Walsh - 2.3-1 +- Update to upstream + * Get rid of security_context_t and fix const declarations. + * Refactor rpm_execcon() into a new setexecfilecon() from Guillem Jover. + +* Tue May 6 2014 Miroslav Grepl - 2.2.2-8 +- Add selinux_openssh_contexts_path() + +* Thu Apr 24 2014 Vít Ondruch - 2.2.2-7 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.1 + +* Mon Feb 24 2014 Dan Walsh - 2.2.2-6 +- Fix spelling mistake in man page + +* Thu Feb 20 2014 Dan Walsh - 2.2.2-5 +- More go bindings +- restorecon, getpidcon, setexeccon + +* Fri Feb 14 2014 Dan Walsh - 2.2.2-4 +- Add additional go bindings for get*con calls +- Add go bindings test command +- Modify man pages of set*con calls to mention that they are thread specific + +* Fri Jan 24 2014 Dan Walsh - 2.2.2-3 +- Move selinux.go to /usr/lib64/golang/src/pkg/github.com/selinux/selinux.go +- Add Int_to_mcs function to generate MCS labels from integers. + +* Tue Jan 14 2014 Dan Walsh - 2.2.2-2 +- Add ghost flag for /var/run/setrans + +* Mon Jan 6 2014 Dan Walsh - 2.2.2-1 +- Update to upstream + * Fix userspace AVC handling of per-domain permissive mode. +- Verify context is not null when passed into *setfilecon_raw + +* Fri Dec 27 2013 Adam Williamson - 2.2.1-6 +- revert unexplained change to rhat.patch which broke SELinux disablement + +* Mon Dec 23 2013 Dan Walsh - 2.2.1-5 +- Verify context is not null when passed into lsetfilecon_raw + +* Wed Dec 18 2013 Dan Walsh - 2.2.1-4 +- Mv selinux.go to /usr/share/gocode/src/selinux + +* Tue Dec 17 2013 Dan Walsh - 2.2.1-3 +- Add golang support to selinux. + +* Thu Dec 5 2013 Dan Walsh - 2.2.1-2 +- Remove togglesebool man page + +* Mon Nov 25 2013 Dan Walsh - 2.2.1-1 +- Update to upstream + * Remove -lpthread from pkg-config file; it is not required. +- Add support for policy compressed with xv + +* Thu Oct 31 2013 Dan Walsh - 2.2-1 +- Update to upstream + * Fix avc_has_perm() returns -1 even when SELinux is in permissive mode. + * Support overriding Makefile RANLIB from Sven Vermeulen. + * Update pkgconfig definition from Sven Vermeulen. + * Mount sysfs before trying to mount selinuxfs from Sven Vermeulen. + * Fix man pages from Laurent Bigonville. + * Support overriding PATH and LIBBASE in Makefiles from Laurent Bigonville. + * Fix LDFLAGS usage from Laurent Bigonville + * Avoid shadowing stat in load_mmap from Joe MacDonald. + * Support building on older PCRE libraries from Joe MacDonald. + * Fix handling of temporary file in sefcontext_compile from Dan Walsh. + * Fix procattr cache from Dan Walsh. + * Define python constants for getenforce result from Dan Walsh. + * Fix label substitution handling of / from Dan Walsh. + * Add selinux_current_policy_path from Dan Walsh. + * Change get_context_list to only return good matches from Dan Walsh. + * Support udev-197 and higher from Sven Vermeulen and Dan Walsh. + * Add support for local substitutions from Dan Walsh. + * Change setfilecon to not return ENOSUP if context is already correct from Dan Walsh. + * Python wrapper leak fixes from Dan Walsh. + * Export SELINUX_TRANS_DIR definition in selinux.h from Dan Walsh. + * Add selinux_systemd_contexts_path from Dan Walsh. + * Add selinux_set_policy_root from Dan Walsh. + * Add man page for sefcontext_compile from Dan Walsh. + +* Fri Oct 4 2013 Dan Walsh - 2.1.13-21 +- Add systemd_contexts support +- Do substitutions on a local sub followed by a dist sub + +* Thu Oct 3 2013 Dan Walsh - 2.1.13-20 +- Eliminate requirement on pthread library, by applying patch for Jakub Jelinek +Resolves #1013801 + +* Mon Sep 16 2013 Dan Walsh - 2.1.13-19 +- Fix handling of libselinux getconlist with only one entry + +* Tue Sep 3 2013 Dan Walsh - 2.1.13-17 +- Add Python constants for SELinux enforcing modes + +* Sat Aug 03 2013 Fedora Release Engineering - 2.1.13-17 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Fri Jun 28 2013 Dan Walsh - 2.1.13-16 +- Add sefcontext_compile.8 man page +- Add Russell Coker patch to fix man pages +- Add patches from Laurent Bigonville to fix Makefiles for debian. +- modify spec file to use %%{_prefix}/lib + +* Mon May 6 2013 Dan Walsh - 2.1.13-15 +- Fix patch that Handles substitutions for / + +* Wed Apr 17 2013 Dan Walsh - 2.1.13-14 +- Handle substitutions for / +- semanage fcontext -a -e / /opt/rh/devtoolset-2/root + +* Tue Apr 9 2013 Dan Walsh - 2.1.13-13 +- Add Eric Paris patch to fix procattr calls after a fork. + +* Tue Mar 26 2013 Dan Walsh - 2.1.13-12 +- Move secolor.conf.5 into mcstrans package and out of libselinux + +* Wed Mar 20 2013 Dan Walsh - 2.1.13-11 +- Fix python bindings for selinux_check_access + +* Tue Mar 19 2013 Dan Walsh - 2.1.13-10 +- Fix reseting the policy root in matchpathcon + +* Wed Mar 6 2013 Dan Walsh - 2.1.13-9 +- Cleanup setfcontext_compile atomic patch +- Add matchpathcon -P /etc/selinux/mls support by allowing users to set alternate root +- Make sure we set exit codes from selinux_label calls to ENOENT or SUCCESS + +* Wed Mar 6 2013 Dan Walsh - 2.1.13-8 +- Make setfcontext_compile atomic + +* Wed Mar 6 2013 Dan Walsh - 2.1.13-7 +- Fix memory leak in set*con calls. + +* Thu Feb 28 2013 Dan Walsh - 2.1.13-6 +- Move matchpathcon to -utils package +- Remove togglesebool + +* Thu Feb 21 2013 Dan Walsh - 2.1.13-5 +- Fix selinux man page to reflect what current selinux policy is. + +* Fri Feb 15 2013 Dan Walsh - 2.1.13-4 +- Add new constant SETRANS_DIR which points to the directory where mstransd can find the socket and libvirt can write its translations files. + +* Fri Feb 15 2013 Dan Walsh - 2.1.13-3 +- Bring back selinux_current_policy_path + +* Thu Feb 14 2013 Dan Walsh - 2.1.13-2 +- Revert some changes which are causing the wrong policy version file to be created + +* Thu Feb 7 2013 Dan Walsh - 2.1.13-1 +- Update to upstream + * audit2why: make sure path is nul terminated + * utils: new file context regex compiler + * label_file: use precompiled filecontext when possible + * do not leak mmapfd + * sefcontontext_compile: Add error handling to help debug problems in libsemanage. + * man: make selinux.8 mention service man pages + * audit2why: Fix segfault if finish() called twice + * audit2why: do not leak on multiple init() calls + * mode_to_security_class: interface to translate a mode_t in to a security class + * audit2why: Cleanup audit2why analysys function + * man: Fix program synopsis and function prototypes in man pages + * man: Fix man pages formatting + * man: Fix typo in man page + * man: Add references and man page links to _raw function variants + * Use ENOTSUP instead of EOPNOTSUPP for getfilecon functions + * man: context_new(3): fix the return value description + * selinux_status_open: handle error from sysconf + * selinux_status_open: do not leak statusfd on exec + * Fix errors found by coverity + * Change boooleans.subs to booleans.subs_dist. + * optimize set*con functions + * pkg-config do not specifc ruby version + * unmap file contexts on selabel_close() + * do not leak file contexts with mmap'd backend + * sefcontext_compile: do not leak fd on error + * matchmediacon: do not leak fd + * src/label_android_property: do not leak fd on error + +* Sun Jan 27 2013 Dan Walsh - 2.1.12-20 +- Update to latest patches from eparis/Upstream + +* Fri Jan 25 2013 Dan Walsh - 2.1.12-19 +- Update to latest patches from eparis/Upstream + +* Wed Jan 23 2013 Dan Walsh - 2.1.12-18 +- Try procatt speedup patch again + +* Wed Jan 23 2013 Dan Walsh - 2.1.12-17 +- Roll back procattr speedups since it seems to be screwing up systemd labeling. + +* Tue Jan 22 2013 Dan Walsh - 2.1.12-16 +- Fix tid handling for setfscreatecon, old patch still broken in libvirt + +* Wed Jan 16 2013 Dan Walsh - 2.1.12-15 +- Fix tid handling for setfscreatecon, old patch still broken in libvirt + +* Mon Jan 14 2013 Dan Walsh - 2.1.12-14 +- setfscreatecon after fork was broken by the Set*con patch. +- We needed to reset the thread variables after a fork. + +* Thu Jan 10 2013 Dan Walsh - 2.1.12-13 +- Fix setfscreatecon call to handle failure mode, which was breaking udev + +* Wed Jan 9 2013 Dan Walsh - 2.1.12-12 +- Ondrej Oprala patch to optimize set*con functions +- Set*con now caches the security context and only re-sets it if it changes. + +* Tue Jan 8 2013 Dan Walsh - 2.1.12-11 +- Rebuild against latest libsepol + +* Fri Jan 4 2013 Dan Walsh - 2.1.12-10 +- Update to latest patches from eparis/Upstream +- Fix errors found by coverity +- set the sepol_compute_av_reason_buffer flag to 0. This means calculate denials only? +- audit2why: remove a useless policy vers variable +- audit2why: use the new constraint information + +* Mon Nov 19 2012 Dan Walsh - 2.1.12-9 +- Rebuild with latest libsepol + +* Fri Nov 16 2012 Dan Walsh - 2.1.12-8 +- Return EPERM if login program can not reach default label for user +- Attempt to return container info from audit2why + +* Thu Nov 1 2012 Dan Walsh - 2.1.12-7 +- Apply patch from eparis to fix leaked file descriptor in new labeling code + +* Fri Oct 19 2012 Dan Walsh - 2.1.12-6 +- Add new function mode_to_security_class which takes mode instead of a string. +- Possibly will be used with coreutils. + +* Mon Oct 15 2012 Dan Walsh - 2.1.12-5 +- Add back selinuxconlist and selinuxdefcon man pages + +* Mon Oct 15 2012 Dan Walsh - 2.1.12-4 +- Fix segfault from calling audit2why.finish() multiple times + +* Fri Oct 12 2012 Dan Walsh - 2.1.12-3 +- Fix up selinux man page to reference service man pages + +* Wed Sep 19 2012 Dan Walsh - 2.1.12-2 +- Rebuild with fixed libsepol + +* Thu Sep 13 2012 Dan Walsh - 2.1.12-1 +- Update to upstream + * Add support for lxc_contexts_path + * utils: add service to getdefaultcon + * libsemanage: do not set soname needlessly + * libsemanage: remove PYTHONLIBDIR and ruby equivalent + * boolean name equivalency + * getsebool: support boolean name substitution + * Add man page for new selinux_boolean_sub function. + * expose selinux_boolean_sub + * matchpathcon: add -m option to force file type check + * utils: avcstat: clear sa_mask set + * seusers: Check for strchr failure + * booleans: initialize pointer to silence coveriety + * stop messages when SELinux disabled + * label_file: use PCRE instead of glibc regex functions + * label_file: remove all typedefs + * label_file: move definitions to include file + * label_file: do string to mode_t conversion in a helper function + * label_file: move error reporting back into caller + * label_file: move stem/spec handling to header + * label_file: drop useless ncomp field from label_file data + * label_file: move spec_hasMetaChars to header + * label_file: fix potential read past buffer in spec_hasMetaChars + * label_file: move regex sorting to the header + * label_file: add accessors for the pcre extra data + * label_file: only run regex files one time + * label_file: new process_file function + * label_file: break up find_stem_from_spec + * label_file: struct reorg + * label_file: only run array once when sorting + * Ensure that we only close the selinux netlink socket once. + * improve the file_contexts.5 manual page + +* Fri Aug 03 2012 David Malcolm - 2.1.11-6 +- rebuild for https://fedoraproject.org/wiki/Features/Python_3.3 + +* Wed Aug 1 2012 David Malcolm - 2.1.11-5 +- make with_python3 be conditional on fedora + +* Thu Jul 19 2012 Fedora Release Engineering - 2.1.11-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 16 2012 Dan Walsh - 2.1.11-3 +- Move the tmpfiles.d content from /etc/tmpfiles.d to /usr/lib/tmpfiles.d + +* Fri Jul 13 2012 Dan Walsh - 2.1.11-2 +- Revert Eric Paris Patch for selinux_binary_policy_path + +* Wed Jul 4 2012 Dan Walsh - 2.1.11-1 +- Update to upstream + * Fortify source now requires all code to be compiled with -O flag + * asprintf return code must be checked + * avc_netlink_recieve handle EINTR + * audit2why: silence -Wmissing-prototypes warning + * libsemanage: remove build warning when build swig c files + * matchpathcon: bad handling of symlinks in / + * seusers: remove unused lineno + * seusers: getseuser: gracefully handle NULL service + * New Android property labeling backend + * label_android_property whitespace cleanups + * additional makefile support for rubywrap + +* Mon Jun 11 2012 Dan Walsh - 2.1.10-5 +- Fix booleans.subs name, change function name to selinux_boolean_sub, + add man page, minor fixes to the function + +* Fri May 25 2012 Dan Walsh - 2.1.10-4 +- Fix to compile with Fortify source + * Add -O compiler flag + * Check return code from asprintf +- Fix handling of symbolic links in / by realpath_not_final + +* Tue Apr 17 2012 Dan Walsh - 2.1.10-3 +- Add support for lxc contexts file + +* Fri Mar 30 2012 Dan Walsh - 2.1.10-2 +- Add support fot boolean subs file + +* Thu Mar 29 2012 Dan Walsh - 2.1.10-1 +- Update to upstream + * Fix dead links to www.nsa.gov/selinux + * Remove jump over variable declaration + * Fix old style function definitions + * Fix const-correctness + * Remove unused flush_class_cache method + * Add prototype decl for destructor + * Add more printf format annotations + * Add printf format attribute annotation to die() method + * Fix const-ness of parameters & make usage() methods static + * Enable many more gcc warnings for libselinux/src/ builds + * utils: Enable many more gcc warnings for libselinux/utils builds + * Change annotation on include/selinux/avc.h to avoid upsetting SWIG + * Ensure there is a prototype for 'matchpathcon_lib_destructor' + * Update Makefiles to handle /usrmove + * utils: Stop separating out matchpathcon as something special + * pkg-config to figure out where ruby include files are located + * build with either ruby 1.9 or ruby 1.8 + * assert if avc_init() not called + * take security_deny_unknown into account + * security_compute_create_name(3) + * Do not link against python library, this is considered + * bad practice in debian + * Hide unnecessarily-exported library destructors + +* Thu Feb 16 2012 Dan Walsh - 2.1.9-9 +- Add selinux_current_policy_path to return /sys/fs/selinux/policy if it exists +- Otherwise search for policy on disk + +* Wed Feb 15 2012 Dan Walsh - 2.1.9-8 +- Change selinux_binary_policy_path to return /sys/fs/selinux/policy +- Add selinux_installed_policy_path to return what selinux_binary_policy_path used to return +- avc_has_perm will now return yes if the machine is in permissive mode +- Make work with ruby-1.9 + +* Fri Feb 3 2012 Dan Walsh - 2.1.9-7 +- avc_netlink_recieve should continue to poll if it receinves an EINTR rather + +* Sun Jan 29 2012 Kay Sievers - 2.1.9-6 +- use /sbin/ldconfig, glibc does not provide + /usr/sbin/ldconfig in the RPM database for now + +* Fri Jan 27 2012 Dan Walsh - 2.1.9-5 +- Rebuild with cleaned up upstream to work in /usr + +* Wed Jan 25 2012 Harald Hoyer 2.1.9-4 +- install everything in /usr + https://fedoraproject.org/wiki/Features/UsrMove + +* Mon Jan 23 2012 Dan Walsh - 2.1.9-3 +- Add Dan Berrange code cleanup patches. + +* Wed Jan 4 2012 Dan Walsh - 2.1.9-2 +- Fix selabal_open man page to refer to proper selinux_opt structure + +* Wed Dec 21 2011 Dan Walsh - 2.1.9-1 +-Update to upstream + * Fix setenforce man page to refer to selinux man page + * Cleanup Man pages + * merge freecon with getcon man page + +* Mon Dec 19 2011 Dan Walsh - 2.1.8-5 +- Add patch from Richard Haines + When selabel_lookup found an invalid context with validation enabled, it + always stated it was 'file_contexts' whether media, x, db or file. + The fix is to store the spec file name in the selabel_lookup_rec on + selabel_open and use this as output for logs. Also a minor fix if key is + NULL to stop seg faults. +- Fix setenforce manage page. + +* Thu Dec 15 2011 Dan Walsh - 2.1.8-4 +- Rebuild with new libsepol + +* Tue Dec 6 2011 Dan Walsh - 2.1.8-2 +- Fix setenforce man page, from Miroslav Grepl + +* Tue Dec 6 2011 Dan Walsh - 2.1.8-1 +- Upgrade to upstream + * selinuxswig_python.i: don't make syscall if it won't change anything + * Remove assert in security_get_boolean_names(3) + * Mapped compute functions now obey deny_unknown flag + * get_default_type now sets EINVAL if no entry. + * return EINVAL if invalid role selected + * Updated selabel_file(5) man page + * Updated selabel_db(5) man page + * Updated selabel_media(5) man page + * Updated selabel_x(5) man page + * Add man/man5 man pages + * Add man/man5 man pages + * Add man/man5 man pages + * use -W and -Werror in utils + +* Tue Nov 29 2011 Dan Walsh - 2.1.7-2 +- Change python binding for restorecon to check if the context matches. +- If it does do not reset + +* Fri Nov 4 2011 Dan Walsh - 2.1.7-1 +- Upgrade to upstream + * Makefiles: syntax, convert all ${VAR} to $(VAR) + * load_policy: handle selinux=0 and /sys/fs/selinux not exist + * regenerate .pc on VERSION change + * label: cosmetic cleanups + * simple interface for access checks + * Don't reinitialize avc_init if it has been called previously + * seusers: fix to handle large sets of groups + * audit2why: close fd on enomem + * rename and export symlink_realpath + * label_file: style changes to make Eric happy. + +* Mon Oct 24 2011 Dan Walsh - 2.1.6-4 +- Apply libselinux patch to handle large groups in seusers. + +* Wed Oct 19 2011 Dan Walsh - 2.1.6-3 +- Add selinux_check_access function. Needed for passwd, chfn, chsh + +* Thu Sep 22 2011 Dan Walsh - 2.1.6-2 +- Handle situation where selinux=0 passed to the kernel and both /selinux and + +* Mon Sep 19 2011 Dan Walsh - 2.1.6-1 +-Update to upstream + * utils: matchpathcon: remove duplicate declaration + * src: matchpathcon: use myprintf not fprintf + * src: matchpathcon: make sure resolved path starts + * put libselinux.so.1 in /lib not /usr/lib + * tree: default make target to all not + +* Wed Sep 14 2011 Dan Walsh - 2.1.5-5 +- Switch to use ":" as prefix separator rather then ";" + +* Thu Sep 8 2011 Ville Skyttä - 2.1.5-4 +- Avoid unnecessary shell invocation in %%post. + +* Tue Sep 6 2011 Dan Walsh - 2.1.5-3 +- Fix handling of subset labeling that is causing segfault in restorecon + +* Fri Sep 2 2011 Dan Walsh - 2.1.5-2 +- Change matchpathcon_init_prefix and selabel_open to allow multiple initial +prefixes. Now you can specify a ";" separated list of prefixes and the +labeling system will only load regular expressions that match these prefixes. + +* Tue Aug 30 2011 Dan Walsh - 2.1.5-1 +- Change matchpatcon to use proper myprintf +- Fix symlink_realpath to always include "/" +- Update to upstream + * selinux_file_context_verify function returns wrong value. + * move realpath helper to matchpathcon library + * python wrapper makefile changes + +* Mon Aug 22 2011 Dan Walsh - 2.1.4-2 +- Move to new Makefile that can build with or without PYTHON being set + +* Thu Aug 18 2011 Dan Walsh - 2.1.4-1 +-Update to upstream +2.1.4 2011-0817 + * mapping fix for invalid class/perms after selinux_set_mapping + * audit2why: work around python bug not defining + * resolv symlinks and dot directories before matching + +2.1.2 2011-0803 + * audit2allow: do not print statistics + * make python bindings for restorecon work on relative path + * fix python audit2why binding error + * support new python3 functions + * do not check fcontext duplicates on use + * Patch for python3 for libselinux + +2.1.1 2011-08-02 + * move .gitignore into utils + * new setexecon utility + * selabel_open fix processing of substitution files + * mountpoint changing patch. + * simplify SRCS in Makefile + +2.1.1 2011-08-01 + * Remove generated files, introduce more .gitignore + + + +* Thu Jul 28 2011 Dan Walsh - 2.1.0-1 +-Update to upstream + * Release, minor version bump + * Give correct names to mount points in load_policy by Dan Walsh. + * Make sure selinux state is reported correctly if selinux is disabled or + fails to load by Dan Walsh. + * Fix crash if selinux_key_create was never called by Dan Walsh. + * Add new file_context.subs_dist for distro specific filecon substitutions + by Dan Walsh. + * Update man pages for selinux_color_* functions by Richard Haines. + +* Mon Jun 13 2011 Dan Walsh - 2.0.102-6 +- Only call dups check within selabel/matchpathcon if you are validating the +context +- This seems to speed the loading of labels by 4 times. + +* Fri Apr 29 2011 Dan Walsh - 2.0.102-5 +- Move /selinux to /sys/fs/selinux +- Add selinuxexeccon +- Add realpath to matchpathcon to handle matchpathcon * type queries. + +* Thu Apr 21 2011 Dan Walsh - 2.0.102-4 +- Update for latest libsepol + +* Mon Apr 18 2011 Dan Walsh - 2.0.102-3 +- Update for latest libsepol + +* Wed Apr 13 2011 Dan Walsh - 2.0.102-2 +- Fix restorecon python binding to accept relative paths + +* Tue Apr 12 2011 Dan Walsh - 2.0.102-1 +-Update to upstream + * Give correct names to mount points in load_policy by Dan Walsh. + * Make sure selinux state is reported correctly if selinux is disabled or + fails to load by Dan Walsh. + * Fix crash if selinux_key_create was never called by Dan Walsh. + * Add new file_context.subs_dist for distro specific filecon substitutions + by Dan Walsh. + * Update man pages for selinux_color_* functions by Richard Haines. + +* Wed Apr 6 2011 Dan Walsh - 2.0.101-1 +- Clean up patch to make handling of constructor cleanup more portable + * db_language object class support for selabel_lookup from KaiGai Kohei. + * Library destructors for thread local storage keys from Eamon Walsh. + +* Tue Apr 5 2011 Dan Walsh - 2.0.99-5 +- Add distribution subs path + +* Tue Apr 5 2011 Dan Walsh - 2.0.99-4 +Add patch from dbhole@redhat.com to initialize thread keys to -1 +Errors were being seen in libpthread/libdl that were related +to corrupt thread specific keys. Global destructors that are called on dl +unload. During destruction delete a thread specific key without checking +if it has been initialized. Since the constructor is not called each time +(i.e. key is not initialized with pthread_key_create each time), and the +default is 0, there is a possibility that key 0 for an active thread gets +deleted. This is exactly what is happening in case of OpenJDK. + +Workaround patch that initializes the key to -1. Thus if the constructor is not +called, the destructor tries to delete key -1 which is deemed invalid by +pthread_key_delete, and is ignored. + +* Tue Apr 5 2011 Dan Walsh - 2.0.99-3 +- Call fini_selinuxmnt if selinux is disabled, to cause is_selinux_disabled() to report correct data + +* Fri Apr 1 2011 Dan Walsh - 2.0.99-2 +- Change mount source options to use "proc" and "selinuxfs" + +* Tue Mar 1 2011 Dan Walsh - 2.0.99-1 +- Update to upstream + * Turn off default user handling when computing user contexts by Dan Walsh + +* Tue Feb 08 2011 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Feb 1 2011 Dan Walsh - 2.0.98-3 +- Fixup selinux man page + +* Tue Jan 18 2011 Dan Walsh - 2.0.98-2 +- Fix Makefile to use pkg-config --cflags python3 to discover include paths + +* Tue Dec 21 2010 Dan Walsh - 2.0.98-1 +- Update to upstream + - Turn off fallback in to SELINUX_DEFAULTUSER in get_context_list + +* Mon Dec 6 2010 Dan Walsh - 2.0.97-1 +- Update to upstream + * Thread local storage fixes from Eamon Walsh. + +* Sat Dec 4 2010 Dan Walsh - 2.0.96-9 +- Add /etc/tmpfiles.d support for /var/run/setrans + +* Wed Nov 24 2010 Dan Walsh - 2.0.96-8 +- Ghost /var/run/setrans + +* Wed Sep 29 2010 jkeating - 2.0.96-7 +- Rebuilt for gcc bug 634757 + +* Thu Sep 16 2010 Adam Tkac - 2.0.96-6 +- rebuild via updated swig (#624674) + +* Sun Aug 22 2010 Dan Walsh - 2.0.96-5 +- Update for python 3.2a1 + +* Tue Jul 27 2010 Dan Walsh - 2.0.96-4 +- Turn off fallback in to SELINUX_DEFAULTUSER in get_context_list + +* Wed Jul 21 2010 David Malcolm - 2.0.96-3 +- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild + +* Fri Jun 25 2010 Dan Walsh - 2.0.96-2 +- Turn off messages in audit2why + +* Wed Mar 24 2010 Dan Walsh - 2.0.96-1 +- Update to upstream + * Add const qualifiers to public API where appropriate by KaiGai Kohei. + +2.0.95 2010-06-10 + * Remove duplicate slashes in paths in selabel_lookup from Chad Sellers + * Adds a chcon method to the libselinux python bindings from Steve Lawrence +- add python3 subpackage from David Malcolm + +* Wed Mar 24 2010 Dan Walsh - 2.0.94-1 +* Set errno=EINVAL for invalid contexts from Dan Walsh. + +* Tue Mar 16 2010 Dan Walsh - 2.0.93-1 +- Update to upstream + * Show strerror for security_getenforce() by Colin Waters. + * Merged selabel database support by KaiGai Kohei. + * Modify netlink socket blocking code by KaiGai Kohei. + +* Sun Mar 7 2010 Dan Walsh - 2.0.92-1 +- Update to upstream + * Fix from Eric Paris to fix leak on non-selinux systems. + * regenerate swig wrappers + * pkgconfig fix to respect LIBDIR from Dan Walsh. + +* Wed Feb 24 2010 Dan Walsh - 2.0.91-1 +- Update to upstream + * Change the AVC to only audit the permissions specified by the + policy, excluding any permissions specified via dontaudit or not + specified via auditallow. + * Fix compilation of label_file.c with latest glibc headers. + +* Mon Feb 22 2010 Dan Walsh - 2.0.90-5 +- Fix potential doublefree on init + +* Thu Feb 18 2010 Dan Walsh - 2.0.90-4 +- Fix libselinux.pc + +* Mon Jan 18 2010 Dan Walsh - 2.0.90-3 +- Fix man page for selinuxdefcon + +* Mon Jan 4 2010 Dan Walsh - 2.0.90-2 +- Free memory on disabled selinux boxes + +* Tue Dec 1 2009 Dan Walsh - 2.0.90-1 +- Update to upstream + * add/reformat man pages by Guido Trentalancia . + * Change exception.sh to be called with bash by Manoj Srivastava + +* Mon Nov 2 2009 Dan Walsh - 2.0.89-2 +- Fix selinuxdefcon man page + +* Mon Nov 2 2009 Dan Walsh - 2.0.89-1 +- Update to upstream + * Add pkgconfig file from Eamon Walsh. + +* Thu Oct 29 2009 Dan Walsh - 2.0.88-1 +- Update to upstream + * Rename and export selinux_reset_config() + +* Tue Sep 8 2009 Dan Walsh - 2.0.87-1 +- Update to upstream + * Add exception handling in libselinux from Dan Walsh. This uses a + shell script called exception.sh to generate a swig interface file. + * make swigify + * Make matchpathcon print <> if path not found in fcontext file. + +* Tue Sep 8 2009 Dan Walsh - 2.0.86-2 +- Eliminate -pthread switch in Makefile + +* Tue Sep 8 2009 Dan Walsh - 2.0.86-1 +- Update to upstream + * Removal of reference counting on userspace AVC SID's. + +* Sat Jul 25 2009 Fedora Release Engineering - 2.0.85-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jul 7 2009 Dan Walsh - 2.0.85-1 +- Update to upstream + * Reverted Tomas Mraz's fix for freeing thread local storage to avoid + pthread dependency. + * Removed fini_context_translations() altogether. + * Merged lazy init patch from Stephen Smalley based on original patch + by Steve Grubb. + +* Tue Jul 7 2009 Dan Walsh - 2.0.84-1 +- Update to upstream + * Add per-service seuser support from Dan Walsh. + * Let load_policy gracefully handle selinuxfs being mounted from Stephen Smalley. + * Check /proc/filesystems before /proc/mounts for selinuxfs from Eric + Paris. + +* Wed Jun 24 2009 Dan Walsh - 2.0.82-2 +- Add provices ruby(selinux) + +* Tue Jun 23 2009 Dan Walsh - 2.0.82-1 +- Update to upstream + * Fix improper use of thread local storage from Tomas Mraz . + * Label substitution support from Dan Walsh. + * Support for labeling virtual machine images from Dan Walsh. + +* Mon May 18 2009 Dan Walsh - 2.0.81-1 +- Update to upstream + * Trim / from the end of input paths to matchpathcon from Dan Walsh. + * Fix leak in process_line in label_file.c from Hiroshi Shinji. + * Move matchpathcon to /sbin, add matchpathcon to clean target from Dan Walsh. + * getdefaultcon to print just the correct match and add verbose option from Dan Walsh. + +* Wed Apr 8 2009 Dan Walsh - 2.0.80-1 +- Update to upstream + * deny_unknown wrapper function from KaiGai Kohei. + * security_compute_av_flags API from KaiGai Kohei. + * Netlink socket management and callbacks from KaiGai Kohei. + +* Fri Apr 3 2009 Dan Walsh - 2.0.79-6 +- Fix Memory Leak + +* Thu Apr 2 2009 Dan Walsh - 2.0.79-5 +- Fix crash in python + +* Sun Mar 29 2009 Dan Walsh - 2.0.79-4 +- Add back in additional interfaces + +* Fri Mar 27 2009 Dan Walsh - 2.0.79-3 +- Add back in av_decision to python swig + +* Thu Mar 12 2009 Dan Walsh - 2.0.79-1 +- Update to upstream + * Netlink socket handoff patch from Adam Jackson. + * AVC caching of compute_create results by Eric Paris. + +* Tue Mar 10 2009 Dan Walsh - 2.0.78-5 +- Add patch from ajax to accellerate X SELinux +- Update eparis patch + +* Mon Mar 9 2009 Dan Walsh - 2.0.78-4 +- Add eparis patch to accellerate Xwindows performance + +* Mon Mar 9 2009 Dan Walsh - 2.0.78-3 +- Fix URL + +* Fri Mar 6 2009 Dan Walsh - 2.0.78-2 +- Add substitute pattern +- matchpathcon output <> on ENOENT + +* Mon Mar 2 2009 Dan Walsh - 2.0.78-1 +- Update to upstream + * Fix incorrect conversion in discover_class code. + +* Wed Feb 25 2009 Fedora Release Engineering - 2.0.77-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Feb 18 2009 Dan Walsh - 2.0.77-5 +- Add + - selinux_virtual_domain_context_path + - selinux_virtual_image_context_path + +* Tue Jan 6 2009 Dan Walsh - 2.0.77-3 +- Throw exeptions in python swig bindings on failures + +* Tue Jan 6 2009 Dan Walsh - 2.0.77-2 +- Fix restorecon python code + +* Tue Jan 6 2009 Dan Walsh - 2.0.77-1 +- Update to upstream + +* Tue Dec 16 2008 Dan Walsh - 2.0.76-6 +- Strip trailing / for matchpathcon + +* Tue Dec 16 2008 Dan Walsh l - 2.0.76-5 +- Fix segfault if seusers file does not work + +* Fri Dec 12 2008 Dan Walsh - 2.0.76-4 +- Add new function getseuser which will take username and service and return +- seuser and level. ipa will populate file in future. +- Change selinuxdefcon to return just the context by default + +* Sat Nov 29 2008 Ignacio Vazquez-Abrams - 2.0.76-2 +- Rebuild for Python 2.6 + +* Mon Nov 17 2008 Dan Walsh - 2.0.76-1 +- Update to Upstream + * Allow shell-style wildcards in x_contexts file. + +* Mon Nov 17 2008 Dan Walsh - 2.0.75-2 +- Eamon Walsh Patch - libselinux: allow shell-style wildcarding in X names +- Add Restorecon/Install python functions from Luke Macken + +* Fri Nov 7 2008 Dan Walsh - 2.0.75-1 +- Update to Upstream + * Correct message types in AVC log messages. + * Make matchpathcon -V pass mode from Dan Walsh. + * Add man page for selinux_file_context_cmp from Dan Walsh. + +* Tue Sep 30 2008 Dan Walsh - 2.0.73-1 +- Update to Upstream + * New man pages from Dan Walsh. + * Update flask headers from refpolicy trunk from Dan Walsh. + +* Fri Sep 26 2008 Dan Walsh - 2.0.71-6 +- Fix matchpathcon -V call + +* Tue Sep 9 2008 Dan Walsh - 2.0.71-5 +- Add flask definitions for open, X and nlmsg_tty_audit + +* Tue Sep 9 2008 Dan Walsh - 2.0.71-4 +- Add missing get/setkeycreatecon man pages + +* Tue Sep 9 2008 Dan Walsh - 2.0.71-3 +- Split out utilities + +* Tue Sep 9 2008 Dan Walsh - 2.0.71-2 +- Add missing man page links for [lf]getfilecon + +* Tue Aug 5 2008 Dan Walsh - 2.0.71-1 +- Update to Upstream + * Add group support to seusers using %%groupname syntax from Dan Walsh. + * Mark setrans socket close-on-exec from Stephen Smalley. + * Only apply nodups checking to base file contexts from Stephen Smalley. + +* Fri Aug 1 2008 Dan Walsh - 2.0.70-1 +- Update to Upstream + * Merge ruby bindings from Dan Walsh. +- Add support for Linux groups to getseuserbyname + +* Fri Aug 1 2008 Dan Walsh - 2.0.69-2 +- Allow group handling in getseuser call + +* Tue Jul 29 2008 Dan Walsh - 2.0.69-1 +- Update to Upstream + * Handle duplicate file context regexes as a fatal error from Stephen Smalley. + This prevents adding them via semanage. + * Fix audit2why shadowed variables from Stephen Smalley. + * Note that freecon NULL is legal in man page from Karel Zak. + +* Wed Jul 9 2008 Dan Walsh - 2.0.67-4 +- Add ruby support for puppet + +* Tue Jul 8 2008 Dan Walsh - 2.0.67-3 +- Rebuild for new libsepol + +* Sun Jun 29 2008 Dan Walsh - 2.0.67-2 +- Add Karel Zak patch for freecon man page + +* Sun Jun 22 2008 Dan Walsh - 2.0.67-1 +- Update to Upstream + * New and revised AVC, label, and mapping man pages from Eamon Walsh. + * Add swig python bindings for avc interfaces from Dan Walsh. + +* Sun Jun 22 2008 Dan Walsh - 2.0.65-1 +- Update to Upstream + * Fix selinux_file_context_verify() and selinux_lsetfilecon_default() to call matchpathcon_init_prefix if not already initialized. + * Add -q qualifier for -V option of matchpathcon and change it to indicate whether verification succeeded or failed via exit status. + +* Fri May 16 2008 Dan Walsh - 2.0.64-3 +- libselinux no longer neets to telnet -u in post install + +* Wed May 7 2008 Dan Walsh - 2.0.64-2 +- Add sedefaultcon and setconlist commands to dump login context + +* Tue Apr 22 2008 Dan Walsh - 2.0.64-1 +- Update to Upstream + * Fixed selinux_set_callback man page. + * Try loading the max of the kernel-supported version and the libsepol-supported version when no manipulation of the binary policy is needed from Stephen Smalley. + * Fix memory leaks in matchpathcon from Eamon Walsh. + +* Wed Apr 16 2008 Dan Walsh - 2.0.61-4 +- Add Xavior Toth patch for security_id_t in swig + +* Thu Apr 10 2008 Dan Walsh - 2.0.61-3 +- Add avc.h to swig code + +* Wed Apr 9 2008 Dan Walsh - 2.0.61-2 +- Grab the latest policy for the kernel + +* Tue Apr 1 2008 Dan Walsh - 2.0.61-1 +- Update to Upstream + * Man page typo fix from Jim Meyering. + +* Sun Mar 23 2008 Dan Walsh - 2.0.60-1 +- Update to Upstream + * Changed selinux_init_load_policy() to not warn about a failed mount of selinuxfs if selinux was disabled in the kernel. + +* Thu Mar 13 2008 Dan Walsh - 2.0.59-2 +- Fix matchpathcon memory leak + +* Fri Feb 29 2008 Dan Walsh - 2.0.59-1 +- Update to Upstream + * Merged new X label "poly_selection" namespace from Eamon Walsh. + +* Thu Feb 28 2008 Dan Walsh - 2.0.58-1 +- Update to Upstream + * Merged reset_selinux_config() for load policy from Dan Walsh. + +* Thu Feb 28 2008 Dan Walsh - 2.0.57-2 +- Reload library on loading of policy to handle chroot + +* Mon Feb 25 2008 Dan Walsh - 2.0.57-1 +- Update to Upstream + * Merged avc_has_perm() errno fix from Eamon Walsh. + +* Fri Feb 22 2008 Dan Walsh - 2.0.56-1 +- Update to Upstream + * Regenerated Flask headers from refpolicy flask definitions. + +* Wed Feb 13 2008 Dan Walsh - 2.0.55-1 +- Update to Upstream + * Merged compute_member AVC function and manpages from Eamon Walsh. + * Provide more error reporting on load policy failures from Stephen Smalley. + +* Fri Feb 8 2008 Dan Walsh - 2.0.53-1 +- Update to Upstream + * Merged new X label "poly_prop" namespace from Eamon Walsh. + +* Wed Feb 6 2008 Dan Walsh - 2.0.52-1 +- Update to Upstream + * Disable setlocaldefs if no local boolean or users files are present from Stephen Smalley. + * Skip userspace preservebools processing for Linux >= 2.6.22 from Stephen Smalley. + +* Tue Jan 29 2008 Dan Walsh - 2.0.50-1 +- Update to Upstream + * Merged fix for audit2why from Dan Walsh. + +* Fri Jan 25 2008 Dan Walsh - 2.0.49-2 +- Fix audit2why to grab latest policy versus the one selected by the kernel + +* Wed Jan 23 2008 Dan Walsh - 2.0.49-1 +* Merged audit2why python binding from Dan Walsh. + +* Wed Jan 23 2008 Dan Walsh - 2.0.48-1 +* Merged updated swig bindings from Dan Walsh, including typemap for pid_t. + +* Mon Jan 21 2008 Dan Walsh - 2.0.47-4 +- Update to use libsepol-static library + +* Wed Jan 16 2008 Adel Gadllah - 2.0.47-3 +- Move libselinux.a to -static package +- Spec cleanups + +* Tue Jan 15 2008 Dan Walsh - 2.0.47-2 +- Put back libselinux.a + +* Fri Jan 11 2008 Dan Walsh - 2.0.47-1 +- Fix memory references in audit2why and change to use tuples +- Update to Upstream + * Fix for the avc: granted null message bug from Stephen Smalley. + +* Fri Jan 11 2008 Dan Walsh - 2.0.46-6 +- Fix __init__.py specification + +* Tue Jan 8 2008 Dan Walsh - 2.0.46-5 +- Add audit2why python bindings + +* Tue Jan 8 2008 Dan Walsh - 2.0.46-4 +- Add pid_t typemap for swig bindings + +* Thu Jan 3 2008 Dan Walsh - 2.0.46-3 +- smp_mflag + +* Thu Jan 3 2008 Dan Walsh - 2.0.46-2 +- Fix spec file caused by spec review + +* Fri Nov 30 2007 Dan Walsh - 2.0.46-1 +- Upgrade to upstream + * matchpathcon(8) man page update from Dan Walsh. + +* Fri Nov 30 2007 Dan Walsh - 2.0.45-1 +- Upgrade to upstream + * dlopen libsepol.so.1 rather than libsepol.so from Stephen Smalley. + * Based on a suggestion from Ulrich Drepper, defer regex compilation until we have a stem match, by Stephen Smalley. + * A further optimization would be to defer regex compilation until we have a complete match of the constant prefix of the regex - TBD. + +* Thu Nov 15 2007 Dan Walsh - 2.0.43-1 +- Upgrade to upstream + * Regenerated Flask headers from policy. + +* Thu Nov 15 2007 Dan Walsh - 2.0.42-1 +- Upgrade to upstream + * AVC enforcing mode override patch from Eamon Walsh. + * Aligned attributes in AVC netlink code from Eamon Walsh. +- Move libselinux.so back into devel package, procps has been fixed + +* Tue Nov 6 2007 Dan Walsh - 2.0.40-1 +- Upgrade to upstream + * Merged refactored AVC netlink code from Eamon Walsh. + * Merged new X label namespaces from Eamon Walsh. + * Bux fix and minor refactoring in string representation code. + +* Fri Oct 5 2007 Dan Walsh - 2.0.37-1 +- Upgrade to upstream + * Merged selinux_get_callback, avc_open, empty string mapping from Eamon Walsh. + +* Fri Sep 28 2007 Dan Walsh - 2.0.36-1 +- Upgrade to upstream + * Fix segfault resulting from missing file_contexts file. + +* Thu Sep 27 2007 Dan Walsh - 2.0.35-2 +- Fix segfault on missing file_context file + +* Wed Sep 26 2007 Dan Walsh - 2.0.35-1 +- Upgrade to upstream + * Make netlink socket close-on-exec to avoid descriptor leakage from Dan Walsh. + * Pass CFLAGS when using gcc for linking from Dennis Gilmore. + +* Mon Sep 24 2007 Dan Walsh - 2.0.34-3 +- Add sparc patch to from Dennis Gilmore to build on Sparc platform + +* Mon Sep 24 2007 Dan Walsh - 2.0.34-2 +- Remove leaked file descriptor + +* Tue Sep 18 2007 Dan Walsh - 2.0.34-1 +- Upgrade to latest from NSA + * Fix selabel option flag setting for 64-bit from Stephen Smalley. + +* Tue Sep 18 2007 Dan Walsh - 2.0.33-2 +- Change matchpatcon to use syslog instead of syserror + +* Thu Sep 13 2007 Dan Walsh - 2.0.33-1 +- Upgrade to latest from NSA + * Re-map a getxattr return value of 0 to a getfilecon return value of -1 with errno EOPNOTSUPP from Stephen Smalley. + * Fall back to the compat code for security_class_to_string and security_av_perm_to_string from Stephen Smalley. + * Fix swig binding for rpm_execcon from James Athey. + +* Thu Sep 6 2007 Dan Walsh - 2.0.31-4 +- Apply James Athway patch to fix rpm_execcon python binding + +* Tue Aug 28 2007 Dan Walsh - 2.0.31-3 +- Move libselinux.so back into main package, breaks procps + +* Thu Aug 23 2007 Dan Walsh - 2.0.31-2 +- Upgrade to upstream + * Fix file_contexts.homedirs path from Todd Miller. + +* Tue Aug 21 2007 Dan Walsh - 2.0.30-2 +- Remove requirement on setransd, Moved to selinux-policy-mls + +* Fri Aug 10 2007 Dan Walsh - 2.0.30-1 +- Move libselinux.so into devel package +- Upgrade to upstream + * Fix segfault resulting from uninitialized print-callback pointer. + * Added x_contexts path function patch from Eamon Walsh. + * Fix build for EMBEDDED=y from Yuichi Nakamura. + * Fix markup problems in selinux man pages from Dan Walsh. + +* Fri Aug 3 2007 Dan Walsh - 2.0.29-1 +- Upgrade to upstream + * Updated version for stable branch. + * Added x_contexts path function patch from Eamon Walsh. + * Fix build for EMBEDDED=y from Yuichi Nakamura. + * Fix markup problems in selinux man pages from Dan Walsh. + * Updated av_permissions.h and flask.h to include new nscd permissions from Dan Walsh. + * Added swigify to top-level Makefile from Dan Walsh. + * Fix for string_to_security_class segfault on x86_64 from Stephen + Smalley. + +* Mon Jul 23 2007 Dan Walsh - 2.0.24-3 +- Apply Steven Smalley patch to fix segfault in string_to_security_class + +* Wed Jul 18 2007 Dan Walsh - 2.0.24-2 +- Fix matchpathcon to set default myprintf + +* Mon Jul 16 2007 Dan Walsh - 2.0.24-1 +- Upgrade to upstream + * Fix for getfilecon() for zero-length contexts from Stephen Smalley. + +* Wed Jul 11 2007 Dan Walsh - 2.0.23-3 +- Update to match flask/access_vectors in policy + +* Tue Jul 10 2007 Dan Walsh - 2.0.23-2 +- Fix man page markup lanquage for translations + +* Tue Jun 26 2007 Dan Walsh - 2.0.23-1 +- Fix semanage segfault on x86 platform + +* Thu Jun 21 2007 Dan Walsh - 2.0.22-1 +- Upgrade to upstream + * Labeling and callback interface patches from Eamon Walsh. + +* Tue Jun 19 2007 Dan Walsh - 2.0.21-2 +- Refactored swig + +* Mon Jun 11 2007 Dan Walsh - 2.0.21-1 +- Upgrade to upstream + * Class and permission mapping support patches from Eamon Walsh. + * Object class discovery support patches from Chris PeBenito. + * Refactoring and errno support in string representation code. + +* Fri Jun 1 2007 Dan Walsh - 2.0.18-1 +- Upgrade to upstream +- Merged patch to reduce size of libselinux and remove need for libsepol for embedded systems from Yuichi Nakamura. + This patch also turns the link-time dependency on libsepol into a runtime (dlopen) dependency even in the non-embedded case. + +2.0.17 2007-05-31 + * Updated Lindent script and reindented two header files. + +* Fri May 4 2007 Dan Walsh - 2.0.16-1 +- Upgrade to upstream + * Merged additional swig python bindings from Dan Walsh. + * Merged helpful message when selinuxfs mount fails patch from Dax Kelson. + +* Tue Apr 24 2007 Dan Walsh - 2.0.14-1 +- Upgrade to upstream + * Merged build fix for avc_internal.c from Joshua Brindle. + +* Mon Apr 23 2007 Dan Walsh - 2.0.13-2 +- Add get_context_list funcitions to swig file + +* Thu Apr 12 2007 Dan Walsh - 2.0.13-1 +- Upgrade to upstream + * Merged rpm_execcon python binding fix, matchpathcon man page fix, and getsebool -a handling for EACCES from Dan Walsh. + +* Thu Apr 12 2007 Dan Walsh - 2.0.12-2 +- Add missing interface + +* Wed Apr 11 2007 Dan Walsh - 2.0.12-1 +- Upgrade to upstream + * Merged support for getting initial contexts from James Carter. + +* Mon Apr 9 2007 Dan Walsh - 2.0.11-1 +- Upgrade to upstream + * Merged userspace AVC patch to follow kernel's behavior for permissive mode in caching previous denials from Eamon Walsh. + * Merged sidput(NULL) patch from Eamon Walsh. + +* Thu Apr 5 2007 Dan Walsh - 2.0.9-2 +- Make rpm_exec swig work + +* Tue Mar 27 2007 Dan Walsh - 2.0.9-1 +- Upgrade to upstream + * Merged class/av string conversion and avc_compute_create patch from Eamon Walsh. + +* Tue Mar 27 2007 Dan Walsh - 2.0.8-1 +- Upgrade to upstream + * Merged fix for avc.h #include's from Eamon Walsh. + +* Thu Mar 22 2007 Dan Walsh - 2.0.7-2 +- Add stdint.h to avc.h + +* Mon Mar 12 2007 Dan Walsh - 2.0.7-1 +- Merged patch to drop support for CACHETRANS=0 config option from Steve Grubb. +- Merged patch to drop support for old /etc/sysconfig/selinux and +- /etc/security policy file layout from Steve Grubb. + +* Thu Mar 8 2007 Dan Walsh - 2.0.5-2 +- Do not fail on permission denied in getsebool + +* Tue Feb 27 2007 Dan Walsh - 2.0.5-1 +- Upgrade to upstream + * Merged init_selinuxmnt() and is_selinux_enabled() improvements from Steve Grubb. + +* Wed Feb 21 2007 Dan Walsh - 2.0.4-1 +- Upgrade to upstream + * Removed sending of setrans init message. + * Merged matchpathcon memory leak fix from Steve Grubb. + +* Tue Feb 20 2007 Dan Walsh - 2.0.2-1 +- Upgrade to upstream + * Merged more swig initializers from Dan Walsh. + +* Sun Feb 18 2007 Dan Walsh - 2.0.1-1 +- Upgrade to upstream + * Merged patch from Todd Miller to convert int types over to C99 style. + +* Wed Feb 7 2007 Dan Walsh - 2.0.0-1 +- Merged patch from Todd Miller to remove sscanf in matchpathcon.c because + of the use of the non-standard format (original patch changed + for style). +- Merged patch from Todd Miller to fix memory leak in matchpathcon.c. + +* Fri Jan 19 2007 Dan Walsh - 1.34.0-2 +- Add context function to python to split context into 4 parts + +* Fri Jan 19 2007 Dan Walsh - 1.34.0-1 +- Upgrade to upstream + * Updated version for stable branch. + +* Wed Jan 17 2007 Dan Walsh - 1.33.6-1 +- Upgrade to upstream + * Merged man page updates to make "apropos selinux" work from Dan Walsh. + +* Wed Jan 17 2007 Dan Walsh - 1.33.5-1 +- Upgrade to upstream + * Merged getdefaultcon utility from Dan Walsh. + +* Mon Jan 15 2007 Dan Walsh - 1.33.4-3 +- Add Ulrich NSCD__GETSERV and NSCD__SHMEMGRP for Uli + +* Fri Jan 12 2007 Dan Walsh - 1.33.4-2 +- Add reference to selinux man page in all man pages to make apropos work +Resolves: # 217881 + +* Thu Jan 11 2007 Dan Walsh - 1.33.4-1 +- Upstream wanted some minor changes, upgrading to keep api the same +- Upgrade to upstream + * Merged selinux_check_securetty_context() and support from Dan Walsh. +Resolves: #200110 + +* Fri Jan 5 2007 Dan Walsh - 1.33.3-3 +- Cleanup patch + +* Fri Jan 5 2007 Dan Walsh - 1.33.3-2 +- Add securetty handling +Resolves: #200110 + +* Thu Jan 4 2007 Dan Walsh - 1.33.3-1 +- Upgrade to upstream + * Merged patch for matchpathcon utility to use file mode information + when available from Dan Walsh. + +* Thu Dec 7 2006 Jeremy Katz - 1.33.2-4 +- rebuild against python 2.5 + +* Wed Dec 6 2006 Dan Walsh - 1.33.2-3 +- Fix matchpathcon to lstat files + +* Thu Nov 30 2006 Dan Walsh - 1.33.2-2 +- Update man page + +* Tue Nov 14 2006 Dan Walsh - 1.33.2-1 +- Upgrade to upstream + +* Fri Nov 3 2006 Dan Walsh - 1.33.1-2 +- Add James Antill patch for login verification of MLS Levels +- MLS ragnes need to be checked, Eg. login/cron. This patch adds infrastructure. + +* Tue Oct 24 2006 Dan Walsh - 1.33.1-1 +- Upgrade to latest from NSA + * Merged updated flask definitions from Darrel Goeddel. + This adds the context security class, and also adds + the string definitions for setsockcreate and polmatch. + +* Tue Oct 17 2006 Dan Walsh - 1.32-1 +- Upgrade to latest from NSA + * Updated version for release. + +* Sun Oct 01 2006 Jesse Keating - 1.30.29-2 +- rebuilt for unwind info generation, broken in gcc-4.1.1-21 + +* Fri Sep 29 2006 Dan Walsh - 1.30.29-1 +- Upgrade to latest from NSA + * Merged av_permissions.h update from Steve Grubb, + adding setsockcreate and polmatch definitions. + +* Wed Sep 27 2006 Jeremy Katz - 1.30.28-3 +- really make -devel depend on libsepol-devel + +* Wed Sep 27 2006 Dan Walsh - 1.30.28-2 +- Add sgrubb patch for polmatch + +* Wed Sep 13 2006 Dan Walsh - 1.30.28-1 +- Upgrade to latest from NSA + * Merged patch from Steve Smalley to fix SIGPIPE in setrans_client + +* Tue Sep 5 2006 Jeremy Katz - 1.30.27-2 +- have -devel require libsepol-devel + +* Thu Aug 24 2006 Dan Walsh - 1.30.27-1 +- Upgrade to latest from NSA + * Merged patch to not log avc stats upon a reset from Steve Grubb. + * Applied patch to revert compat_net setting upon policy load. + * Merged file context homedir and local path functions from + Chris PeBenito. + +* Fri Aug 18 2006 Jesse Keating - 1.20.26-2 +- rebuilt with latest binutils to pick up 64K -z commonpagesize on ppc* + (#203001) + +* Sat Aug 12 2006 Dan Walsh - 1.30.25-1 +- Upgrade to latest from NSA + * Merged file context homedir and local path functions from + Chris PeBenito. + * Rework functions that access /proc/pid/attr to access the + per-thread nodes, and unify the code to simplify maintenance. + +* Fri Aug 11 2006 Dan Walsh - 1.30.24-1 +- Upgrade to latest from NSA + * Merged return value fix for *getfilecon() from Dan Walsh. + * Merged sockcreate interfaces from Eric Paris. + +* Wed Aug 9 2006 Dan Walsh - 1.30.22-2 +- Fix translation return codes to return size of buffer + +* Tue Aug 1 2006 Dan Walsh - 1.30.22-1 +- Upgrade to latest from NSA + * Merged no-tls-direct-seg-refs patch from Jeremy Katz. + * Merged netfilter_contexts support patch from Chris PeBenito. + +* Tue Aug 1 2006 Dan Walsh - 1.30.20-1 +- Upgrade to latest from NSA + * Merged context_*_set errno patch from Jim Meyering. + +* Tue Aug 1 2006 Jeremy Katz - 1.30.19-5 +- only build non-fpic objects with -mno-tls-direct-seg-refs + +* Tue Aug 1 2006 Jeremy Katz - 1.30.19-4 +- build with -mno-tls-direct-seg-refs on x86 to avoid triggering + segfaults with xen (#200783) + +* Mon Jul 17 2006 Dan Walsh 1.30.19-3 +- Rebuild for new gcc + +* Tue Jul 11 2006 Dan Walsh 1.30.19-2 +- Fix libselinux to not telinit during installs + +* Tue Jul 4 2006 Dan Walsh 1.30.19-1 +- Upgrade to latest from NSA + * Lindent. + * Merged {get,set}procattrcon patch set from Eric Paris. + * Merged re-base of keycreate patch originally by Michael LeMay from Eric Paris. + * Regenerated Flask headers from refpolicy. + * Merged patch from Dan Walsh with: + - Added selinux_file_context_{cmp,verify}. + - Added selinux_lsetfilecon_default. + - Delay translation of contexts in matchpathcon. + +* Wed Jun 21 2006 Dan Walsh 1.30.15-5 +- Yet another change to matchpathcon + +* Wed Jun 21 2006 Dan Walsh 1.30.15-4 +- Turn off error printing in library. Need to compile with DEBUG to get it back + +* Wed Jun 21 2006 Dan Walsh 1.30.15-3 +- Fix error reporting of matchpathcon + +* Mon Jun 19 2006 Dan Walsh 1.30.15-2 +- Add function to compare file context on disk versus contexts in file_contexts file. + +* Fri Jun 16 2006 Dan Walsh 1.30.15-1 +- Upgrade to latest from NSA + * Merged patch from Dan Walsh with: + * Added selinux_getpolicytype() function. + * Modified setrans code to skip processing if !mls_enabled. + * Set errno in the !selinux_mnt case. + * Allocate large buffers from the heap, not on stack. + Affects is_context_customizable, selinux_init_load_policy, + and selinux_getenforcemode. + +* Thu Jun 8 2006 Dan Walsh 1.30.12-2 +- Add selinux_getpolicytype() + +* Thu Jun 1 2006 Dan Walsh 1.30.12-1 +- Upgrade to latest from NSA + * Merged !selinux_mnt checks from Ian Kent. + +* Thu Jun 1 2006 Dan Walsh 1.30.11-2 +- Check for selinux_mnt == NULL + +* Tue May 30 2006 Dan Walsh 1.30.11-1 +- Merged matchmediacon and trans_to_raw_context fixes from + Serge Hallyn. + +* Fri May 26 2006 Dan Walsh 1.30.10-4 +- Remove getseuser + +* Thu May 25 2006 Dan Walsh 1.30.10-3 +- Bump requires to grab latest libsepol + +* Tue May 23 2006 Dan Walsh 1.30.10-2 +- Add BuildRequires for swig + +* Tue May 23 2006 Dan Walsh 1.30.10-1 +- Upgrade to latest from NSA + * Merged simple setrans client cache from Dan Walsh. + Merged avcstat patch from Russell Coker. + * Modified selinux_mkload_policy() to also set /selinux/compat_net + appropriately for the loaded policy. + +* Thu May 18 2006 Dan Walsh 1.30.8-1 +- More fixes for translation cache +- Upgrade to latest from NSA + * Added matchpathcon_fini() function to free memory allocated by + matchpathcon_init(). + +* Wed May 17 2006 Dan Walsh 1.30.7-2 +- Add simple cache to improve translation speed + +* Tue May 16 2006 Dan Walsh 1.30.7-1 +- Upgrade to latest from NSA + * Merged setrans client cleanup patch from Steve Grubb. + +* Tue May 9 2006 Dan Walsh 1.30.6-2 +- Add Russell's AVC patch to handle large numbers + +* Mon May 8 2006 Dan Walsh 1.30.6-1 +- Upgrade to latest from NSA + * Merged getfscreatecon man page fix from Dan Walsh. + * Updated booleans(8) man page to drop references to the old + booleans file and to note that setsebool can be used to set + the boot-time defaults via -P. + +* Mon May 8 2006 Dan Walsh 1.30.5-1 +- Upgrade to latest from NSA + * Merged fix warnings patch from Karl MacMillan. + * Merged setrans client support from Dan Walsh. + This removes use of libsetrans. + * Merged patch to eliminate use of PAGE_SIZE constant from Dan Walsh. + * Merged swig typemap fixes from Glauber de Oliveira Costa. + +* Wed May 3 2006 Dan Walsh 1.30.3-3 +- Change the way translations work, Use setransd/remove libsetrans + +* Tue May 2 2006 Dan Walsh 1.30.3-2 +- Add selinuxswig fixes +- Stop using PAGE_SIZE and start using sysconf(_SC_PAGE_SIZE) + +* Fri Apr 14 2006 Dan Walsh 1.30.3-1 +- Upgrade to latest from NSA + * Added distclean target to Makefile. + * Regenerated swig files. + * Changed matchpathcon_init to verify that the spec file is + a regular file. + * Merged python binding t_output_helper removal patch from Dan Walsh. + +* Tue Apr 11 2006 Dan Walsh 1.30.1-2 +- Fix python bindings for matchpathcon +- Fix booleans man page + +* Mon Mar 27 2006 Dan Walsh 1.30.1-1 +- Merged Makefile PYLIBVER definition patch from Dan Walsh. + +* Fri Mar 10 2006 Dan Walsh 1.30-1 +- Make some fixes so it will build on RHEL4 +- Upgrade to latest from NSA + * Updated version for release. + * Altered rpm_execcon fallback logic for permissive mode to also + handle case where /selinux/enforce is not available. + +* Fri Feb 10 2006 Jesse Keating - 1.29.7-1.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.29.7-1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Jan 20 2006 Dan Walsh 1.29.7-1 +- Upgrade to latest from NSA + * Merged install-pywrap Makefile patch from Joshua Brindle. + +* Wed Jan 18 2006 Dan Walsh 1.29.6-1 +- Upgrade to latest from NSA + * Merged pywrap Makefile patch from Dan Walsh. + +* Fri Jan 13 2006 Dan Walsh 1.29.5-2 +- Split out pywrap in Makefile + +* Fri Jan 13 2006 Dan Walsh 1.29.5-1 +- Upgrade to latest from NSA + * Added getseuser test program. + +* Fri Jan 6 2006 Dan Walsh 1.29.4-1 +- Upgrade to latest from NSA + * Added format attribute to myprintf in matchpathcon.c and + removed obsoleted rootlen variable in init_selinux_config(). + +* Wed Jan 4 2006 Dan Walsh 1.29.3-2 +- Build with new libsepol + +* Wed Jan 4 2006 Dan Walsh 1.29.3-1 +- Upgrade to latest from NSA + * Merged several fixes and improvements from Ulrich Drepper + (Red Hat), including: + - corrected use of getline + - further calls to __fsetlocking for local files + - use of strdupa and asprintf + - proper handling of dirent in booleans code + - use of -z relro + - several other optimizations + * Merged getpidcon python wrapper from Dan Walsh (Red Hat). + +* Sat Dec 24 2005 Dan Walsh 1.29.2-4 +- Add build requires line for libsepol-devel + +* Tue Dec 20 2005 Dan Walsh 1.29.2-3 +- Fix swig call for getpidcon + +* Mon Dec 19 2005 Dan Walsh 1.29.2-2 +- Move libselinux.so to base package + +* Wed Dec 14 2005 Dan Walsh 1.29.2-1 +- Upgrade to latest from NSA + * Merged call to finish_context_translations from Dan Walsh. + This eliminates a memory leak from failing to release memory + allocated by libsetrans. + +* Sun Dec 11 2005 Dan Walsh 1.29.1-3 +- update to latest libsetrans +- Fix potential memory leak + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Dec 8 2005 Dan Walsh 1.29.1-1 +- Update to never version + * Merged patch for swig interfaces from Dan Walsh. + +* Wed Dec 7 2005 Dan Walsh 1.28-1 +- Update to never version + +* Wed Dec 7 2005 Dan Walsh 1.27.28-2 +- Fix some of the python swig objects + +* Thu Dec 1 2005 Dan Walsh 1.27.28-1 +- Update to latest from NSA + * Added MATCHPATHCON_VALIDATE flag for set_matchpathcon_flags() and + modified matchpathcon implementation to make context validation/ + canonicalization optional at matchpathcon_init time, deferring it + to a successful matchpathcon by default unless the new flag is set + by the caller. + * Added matchpathcon_init_prefix() interface, and + reworked matchpathcon implementation to support selective + loading of file contexts entries based on prefix matching + between the pathname regex stems and the specified path + prefix (stem must be a prefix of the specified path prefix). + +* Wed Nov 30 2005 Dan Walsh 1.27.26-1 +- Update to latest from NSA + * Change getsebool to return on/off instead of active/inactive + +* Tue Nov 29 2005 Dan Walsh 1.27.25-1 +- Update to latest from NSA + * Added -f file_contexts option to matchpathcon util. + Fixed warning message in matchpathcon_init(). + * Merged Makefile python definitions patch from Dan Walsh. + +* Mon Nov 28 2005 Dan Walsh 1.27.23-1 +- Update to latest from NSA + * Merged swigify patch from Dan Walsh. + +* Mon Nov 28 2005 Dan Walsh 1.27.22-4 +- Separate out libselinux-python bindings into separate rpm + +* Thu Nov 17 2005 Dan Walsh 1.27.22-3 +- Read libsetrans requirement + +* Thu Nov 17 2005 Dan Walsh 1.27.22-2 +- Add python bindings + +* Wed Nov 16 2005 Dan Walsh 1.27.22-1 +- Update to latest from NSA + * Merged make failure in rpm_execcon non-fatal in permissive mode + patch from Ivan Gyurdiev. + +* Tue Nov 15 2005 Dan Walsh 1.27.21-2 +- Remove requirement for libsetrans + +* Tue Nov 8 2005 Dan Walsh 1.27.21-1 +- Update to latest from NSA + * Added MATCHPATHCON_NOTRANS flag for set_matchpathcon_flags() + and modified matchpathcon_init() to skip context translation + if it is set by the caller. + +* Tue Nov 8 2005 Dan Walsh 1.27.20-1 +- Update to latest from NSA + * Added security_canonicalize_context() interface and + set_matchpathcon_canoncon() interface for obtaining + canonical contexts. Changed matchpathcon internals + to obtain canonical contexts by default. Provided + fallback for kernels that lack extended selinuxfs context + interface. +- Patch to not translate mls when calling setfiles + +* Mon Nov 7 2005 Dan Walsh 1.27.19-1 +- Update to latest from NSA + * Merged seusers parser changes from Ivan Gyurdiev. + * Merged setsebool to libsemanage patch from Ivan Gyurdiev. + * Changed seusers parser to reject empty fields. + +* Fri Nov 4 2005 Dan Walsh 1.27.18-1 +- Update to latest from NSA + * Merged seusers empty level handling patch from Jonathan Kim (TCS). + +* Thu Nov 3 2005 Dan Walsh 1.27.17-4 +- Rebuild for latest libsepol + +* Mon Oct 31 2005 Dan Walsh 1.27.17-2 +- Rebuild for latest libsepol + +* Wed Oct 26 2005 Dan Walsh 1.27.17-1 +- Change default to __default__ + +* Wed Oct 26 2005 Dan Walsh 1.27.14-3 +- Change default to __default__ + +* Tue Oct 25 2005 Dan Walsh 1.27.14-2 +- Add selinux_translations_path + +* Tue Oct 25 2005 Dan Walsh 1.27.14-1 +- Update to latest from NSA + * Merged selinux_path() and selinux_homedir_context_path() + functions from Joshua Brindle. + +* Fri Oct 21 2005 Dan Walsh 1.27.13-2 +- Need to check for /sbin/telinit + +* Thu Oct 20 2005 Dan Walsh 1.27.13-1 +- Update to latest from NSA + * Merged fixes for make DESTDIR= builds from Joshua Brindle. + +* Mon Oct 17 2005 Dan Walsh 1.27.12-1 +- Update to latest from NSA + * Merged get_default_context_with_rolelevel and man pages from + Dan Walsh (Red Hat). + * Updated call to sepol_policydb_to_image for sepol changes. + * Changed getseuserbyname to ignore empty lines and to handle + no matching entry in the same manner as no seusers file. + +* Fri Oct 14 2005 Dan Walsh 1.27.9-2 +- Tell init to reexec itself in post script + +* Fri Oct 7 2005 Dan Walsh 1.27.9-1 +- Update to latest from NSA + * Changed selinux_mkload_policy to try downgrading the + latest policy version available to the kernel-supported version. + * Changed selinux_mkload_policy to fall back to the maximum + policy version supported by libsepol if the kernel policy version + falls outside of the supported range. + +* Fri Oct 7 2005 Dan Walsh 1.27.7-1 +- Update to latest from NSA + * Changed getseuserbyname to fall back to the Linux username and + NULL level if seusers config file doesn't exist unless + REQUIRESEUSERS=1 is set in /etc/selinux/config. + * Moved seusers.conf under $SELINUXTYPE and renamed to seusers. + +* Thu Oct 6 2005 Dan Walsh 1.27.6-1 +- Update to latest from NSA + * Added selinux_init_load_policy() function as an even higher level + interface for the initial policy load by /sbin/init. This obsoletes + the load_policy() function in the sysvinit-selinux.patch. + * Added selinux_mkload_policy() function as a higher level interface + for loading policy than the security_load_policy() interface. + +* Thu Oct 6 2005 Dan Walsh 1.27.4-1 +- Update to latest from NSA + * Merged fix for matchpathcon (regcomp error checking) from Johan + Fischer. Also added use of regerror to obtain the error string + for inclusion in the error message. + +* Tue Oct 4 2005 Dan Walsh 1.27.3-1 +- Update to latest from NSA + * Changed getseuserbyname to not require (and ignore if present) + the MLS level in seusers.conf if MLS is disabled, setting *level + to NULL in this case. + +* Mon Oct 3 2005 Dan Walsh 1.27.2-1 +- Update to latest from NSA + * Merged getseuserbyname patch from Dan Walsh. + +* Thu Sep 29 2005 Dan Walsh 1.27.1-3 +- Fix patch to satisfy upstream + +* Wed Sep 28 2005 Dan Walsh 1.27.1-2 +- Update to latest from NSA +- Add getseuserbyname + +* Fri Sep 16 2005 Dan Walsh 1.26-6 +- Fix patch call + +* Tue Sep 13 2005 Dan Walsh 1.26-5 +- Fix strip_con call + +* Tue Sep 13 2005 Dan Walsh 1.26-3 +- Go back to original libsetrans code + +* Mon Sep 12 2005 Dan Walsh 1.26-2 +- Eliminate forth param from mls context when mls is not enabled. + +* Tue Sep 6 2005 Dan Walsh 1.25.7-1 +- Update from NSA + * Merged modified form of patch to avoid dlopen/dlclose by + the static libselinux from Dan Walsh. Users of the static libselinux + will not have any context translation by default. + +* Thu Sep 1 2005 Dan Walsh 1.25.6-1 +- Update from NSA + * Added public functions to export context translation to + users of libselinux (selinux_trans_to_raw_context, + selinux_raw_to_trans_context). + +* Mon Aug 29 2005 Dan Walsh 1.25.5-1 +- Update from NSA + * Remove special definition for context_range_set; use + common code. + +* Thu Aug 25 2005 Dan Walsh 1.25.4-1 +- Update from NSA + * Hid translation-related symbols entirely and ensured that + raw functions have hidden definitions for internal use. + * Allowed setting NULL via context_set* functions. + * Allowed whitespace in MLS component of context. + * Changed rpm_execcon to use translated functions to workaround + lack of MLS level on upgraded systems. + +* Wed Aug 24 2005 Dan Walsh 1.25.3-2 +- Allow set_comp on unset ranges + +* Wed Aug 24 2005 Dan Walsh 1.25.3-1 +- Merged context translation patch, originally by TCS, + with modifications by Dan Walsh (Red Hat). + +* Wed Aug 17 2005 Dan Walsh 1.25.2-2 +- Apply translation patch + +* Thu Aug 11 2005 Dan Walsh 1.25.2-1 +- Update from NSA + * Merged several fixes for error handling paths in the + AVC sidtab, matchpathcon, booleans, context, and get_context_list + code from Serge Hallyn (IBM). Bugs found by Coverity. + * Removed setupns; migrated to pam. + * Merged patches to rename checkPasswdAccess() from Joshua Brindle. + Original symbol is temporarily retained for compatibility until + all callers are updated. + +* Mon Jul 18 2005 Dan Walsh 1.24.2-1 +- Update makefiles + +* Wed Jun 29 2005 Dan Walsh 1.24.1-1 +- Update from NSA + * Merged security_setupns() from Chad Sellers. +- fix selinuxenabled man page + +* Fri May 20 2005 Dan Walsh 1.23.11-1 +- Update from NSA + * Merged avcstat and selinux man page from Dan Walsh. + * Changed security_load_booleans to process booleans.local + even if booleans file doesn't exist. + +* Fri Apr 29 2005 Dan Walsh 1.23.10-3 +- Fix avcstat to clear totals + +* Fri Apr 29 2005 Dan Walsh 1.23.10-2 +- Add info to man page + +* Fri Apr 29 2005 Dan Walsh 1.23.10-1 +- Update from NSA + * Merged set_selinuxmnt patch from Bill Nottingham (Red Hat). + * Rewrote get_ordered_context_list and helpers, including + changing logic to allow variable MLS fields. + +* Tue Apr 26 2005 Dan Walsh 1.23.8-1 +- Update from NSA + +* Thu Apr 21 2005 Dan Walsh 1.23.7-3 +- Add backin matchpathcon + +* Wed Apr 13 2005 Dan Walsh 1.23.7-2 +- Fix selinux_policy_root man page + +* Wed Apr 13 2005 Dan Walsh 1.23.7-1 +- Change assert(selinux_mnt) to if (!selinux_mnt) return -1; + +* Mon Apr 11 2005 Dan Walsh 1.23.6-1 +- Update from NSA + * Fixed bug in matchpathcon_filespec_destroy. + +* Wed Apr 6 2005 Dan Walsh 1.23.5-1 +- Update from NSA + * Fixed bug in rpm_execcon error handling path. + +* Mon Apr 4 2005 Dan Walsh 1.23.4-1 +- Update from NSA + * Merged fix for set_matchpathcon* functions from Andreas Steinmetz. + * Merged fix for getconlist utility from Andreas Steinmetz. + +* Tue Mar 29 2005 Dan Walsh 1.23.2-3 +- Update from NSA + +* Wed Mar 23 2005 Dan Walsh 1.23.2-2 +- Better handling of booleans + +* Thu Mar 17 2005 Dan Walsh 1.23.2-1 +- Update from NSA + * Merged destructors patch from Tomas Mraz. + +* Thu Mar 17 2005 Dan Walsh 1.23.1-1 +- Update from NSA + * Added set_matchpathcon_flags() function for setting flags + controlling operation of matchpathcon. MATCHPATHCON_BASEONLY + means only process the base file_contexts file, not + file_contexts.homedirs or file_contexts.local, and is for use by + setfiles -c. + * Updated matchpathcon.3 man page. + +* Thu Mar 10 2005 Dan Walsh 1.22-1 +- Update from NSA + +* Tue Mar 8 2005 Dan Walsh 1.21.13-1 +- Update from NSA + * Fixed bug in matchpathcon_filespec_add() - failure to clear fl_head. + +* Tue Mar 1 2005 Dan Walsh 1.21.12-1 +- Update from NSA + * Changed matchpathcon_common to ignore any non-format bits in the mode. + +* Mon Feb 28 2005 Dan Walsh 1.21.11-2 +- Default matchpathcon to regular files if the user specifies a mode + +* Tue Feb 22 2005 Dan Walsh 1.21.11-1 +- Update from NSA + * Merged several fixes from Ulrich Drepper. + +* Mon Feb 21 2005 Dan Walsh 1.21.10-3 +- Fix matchpathcon on eof. + +* Thu Feb 17 2005 Dan Walsh 1.21.10-1 +- Update from NSA + * Merged matchpathcon patch for file_contexts.homedir from Dan Walsh. + * Added selinux_users_path() for path to directory containing + system.users and local.users. + +* Thu Feb 10 2005 Dan Walsh 1.21.9-2 +- Process file_context.homedir + +* Thu Feb 10 2005 Dan Walsh 1.21.9-1 +- Update from NSA + * Changed relabel Makefile target to use restorecon. + +* Tue Feb 8 2005 Dan Walsh 1.21.8-1 +- Update from NSA + * Regenerated av_permissions.h. + +* Wed Feb 2 2005 Dan Walsh 1.21.7-1 +- Update from NSA + * Modified avc_dump_av to explicitly check for any permissions that + cannot be mapped to string names and display them as a hex value. + * Regenerated av_permissions.h. + +* Mon Jan 31 2005 Dan Walsh 1.21.5-1 +- Update from NSA + * Generalized matchpathcon internals, exported more interfaces, + and moved additional code from setfiles into libselinux so that + setfiles can directly use matchpathcon. + +* Fri Jan 28 2005 Dan Walsh 1.21.4-1 +- Update from NSA + * Prevent overflow of spec array in matchpathcon. + * Fixed several uses of internal functions to avoid relocations. + * Changed rpm_execcon to check is_selinux_enabled() and fallback to + a regular execve if not enabled (or unable to determine due to a lack + of /proc, e.g. chroot'd environment). + +* Wed Jan 26 2005 Dan Walsh 1.21.2-1 +- Update from NSA + * Merged minor fix for avcstat from Dan Walsh. + +* Mon Jan 24 2005 Dan Walsh 1.21.1-3 +- rpmexeccon should not fail in permissive mode. + +* Fri Jan 21 2005 Dan Walsh 1.21.1-2 +- fix printf in avcstat + +* Thu Jan 20 2005 Dan Walsh 1.21.1-1 +- Update from NSA + +* Wed Jan 12 2005 Dan Walsh 1.20.1-3 +- Modify matchpathcon to also process file_contexts.local if it exists + +* Wed Jan 12 2005 Dan Walsh 1.20.1-2 +- Add is_customizable_types function call + +* Fri Jan 7 2005 Dan Walsh 1.20.1-1 +- Update to latest from upstream + * Just changing version number to match upstream + +* Wed Dec 29 2004 Dan Walsh 1.19.4-1 +- Update to latest from upstream + * Changed matchpathcon to return -1 with errno ENOENT for + <> entries, and also for an empty file_contexts configuration. + +* Tue Dec 28 2004 Dan Walsh 1.19.3-3 +- Fix link devel libraries + +* Mon Dec 27 2004 Dan Walsh 1.19.3-2 +- Fix unitialized variable in avcstat.c + +* Tue Nov 30 2004 Dan Walsh 1.19.3-1 +- Upgrade to upstream + * Removed some trivial utils that were not useful or redundant. + * Changed BINDIR default to /usr/sbin to match change in Fedora. + * Added security_compute_member. + * Added man page for setcon. + +* Tue Nov 30 2004 Dan Walsh 1.19.2-1 +- Upgrade to upstream + +* Thu Nov 18 2004 Dan Walsh 1.19.1-6 +- Add avcstat program + +* Mon Nov 15 2004 Dan Walsh 1.19.1-4 +- Add lots of missing man pages + +* Fri Nov 12 2004 Dan Walsh 1.19.1-2 +- Fix output of getsebool. + +* Tue Nov 9 2004 Dan Walsh 1.19.1-1 +- Update from upstream, fix setsebool -P segfault + +* Fri Nov 5 2004 Steve Grubb 1.18.1-5 +- Add a patch from upstream. Fixes signed/unsigned issues, and + incomplete structure copy. + +* Thu Nov 4 2004 Dan Walsh 1.18.1-4 +- More fixes from sgrubb, better syslog + +* Thu Nov 4 2004 Dan Walsh 1.18.1-3 +- Have setsebool and togglesebool log changes to syslog + +* Wed Nov 3 2004 Steve Grubb 1.18.1-2 +- Add patch to make setsebool update bool on disk +- Make togglesebool have a rollback capability in case it blows up inflight + +* Tue Nov 2 2004 Dan Walsh 1.18.1-1 +- Upgrade to latest from NSA + +* Thu Oct 28 2004 Steve Grubb 1.17.15-2 +- Changed the location of the utilities to /usr/sbin since + normal users can't use them anyways. + +* Wed Oct 27 2004 Steve Grubb 1.17.15-2 +- Updated various utilities, removed utilities that are for testing, + added man pages. + +* Fri Oct 15 2004 Dan Walsh 1.17.15-1 +- Add -g flag to make +- Upgrade to latest from NSA + * Added rpm_execcon. + +* Fri Oct 1 2004 Dan Walsh 1.17.14-1 +- Upgrade to latest from NSA + * Merged setenforce and removable context patch from Dan Walsh. + * Merged build fix for alpha from Ulrich Drepper. + * Removed copyright/license from selinux_netlink.h - definitions only. + +* Fri Oct 1 2004 Dan Walsh 1.17.13-3 +- Change setenforce to accept Enforcing and Permissive + +* Wed Sep 22 2004 Dan Walsh 1.17.13-2 +- Add alpha patch + +* Mon Sep 20 2004 Dan Walsh 1.17.13-1 +- Upgrade to latest from NSA + +* Thu Sep 16 2004 Dan Walsh 1.17.12-2 +- Add selinux_removable_context_path + +* Tue Sep 14 2004 Dan Walsh 1.17.12-1 +- Update from NSA + * Add matchmediacon + +* Tue Sep 14 2004 Dan Walsh 1.17.11-1 +- Update from NSA + * Merged in matchmediacon changes. + +* Fri Sep 10 2004 Dan Walsh 1.17.10-1 +- Update from NSA + * Regenerated headers for new nscd permissions. + +* Wed Sep 8 2004 Dan Walsh 1.17.9-2 +- Add matchmediacon + +* Wed Sep 8 2004 Dan Walsh 1.17.9-1 +- Update from NSA + * Added get_default_context_with_role. + +* Thu Sep 2 2004 Dan Walsh 1.17.8-2 +- Clean up spec file + * Patch from Matthias Saou + +* Thu Sep 2 2004 Dan Walsh 1.17.8-1 +- Update from NSA + * Added set_matchpathcon_printf. + +* Wed Sep 1 2004 Dan Walsh 1.17.7-1 +- Update from NSA + * Reworked av_inherit.h to allow easier re-use by kernel. + +* Tue Aug 31 2004 Dan Walsh 1.17.6-1 +- Add strcasecmp in selinux_config +- Update from NSA + * Changed avc_has_perm_noaudit to not fail on netlink errors. + * Changed avc netlink code to check pid based on patch by Steve Grubb. + * Merged second optimization patch from Ulrich Drepper. + * Changed matchpathcon to skip invalid file_contexts entries. + * Made string tables private to libselinux. + * Merged strcat->stpcpy patch from Ulrich Drepper. + * Merged matchpathcon man page from Dan Walsh. + * Merged patch to eliminate PLTs for local syms from Ulrich Drepper. + * Autobind netlink socket. + * Dropped compatibility code from security_compute_user. + * Merged fix for context_range_set from Chad Hanson. + * Merged allocation failure checking patch from Chad Hanson. + * Merged avc netlink error message patch from Colin Walters. + + +* Mon Aug 30 2004 Dan Walsh 1.17.5-1 +- Update from NSA + * Merged second optimization patch from Ulrich Drepper. + * Changed matchpathcon to skip invalid file_contexts entries. + * Made string tables private to libselinux. + * Merged strcat->stpcpy patch from Ulrich Drepper. + * Merged matchpathcon man page from Dan Walsh. + * Merged patch to eliminate PLTs for local syms from Ulrich Drepper. + * Autobind netlink socket. + * Dropped compatibility code from security_compute_user. + * Merged fix for context_range_set from Chad Hanson. + * Merged allocation failure checking patch from Chad Hanson. + * Merged avc netlink error message patch from Colin Walters. + +* Mon Aug 30 2004 Dan Walsh 1.17.4-1 +- Update from NSA +- Add optflags + +* Fri Aug 27 2004 Dan Walsh 1.17.3-1 +- Update from NSA + +* Thu Aug 26 2004 Dan Walsh 1.17.2-1 +- Add matchpathcon man page +- Latest from NSA + * Merged patch to eliminate PLTs for local syms from Ulrich Drepper. + * Autobind netlink socket. + * Dropped compatibility code from security_compute_user. + * Merged fix for context_range_set from Chad Hanson. + * Merged allocation failure checking patch from Chad Hanson. + * Merged avc netlink error message patch from Colin Walters. + +* Tue Aug 24 2004 Dan Walsh 1.17.1-1 +- Latest from NSA + * Autobind netlink socket. + * Dropped compatibility code from security_compute_user. + * Merged fix for context_range_set from Chad Hanson. + * Merged allocation failure checking patch from Chad Hanson. + * Merged avc netlink error message patch from Colin Walters. + +* Sun Aug 22 2004 Dan Walsh 1.16.1-1 +- Latest from NSA + +* Thu Aug 19 2004 Colin Walters 1.16-1 +- New upstream version + +* Tue Aug 17 2004 Dan Walsh 1.15.7-1 +- Latest from Upstream + +* Mon Aug 16 2004 Dan Walsh 1.15.6-1 +- Fix man pages + +* Mon Aug 16 2004 Dan Walsh 1.15.5-1 +- Latest from Upstream + +* Fri Aug 13 2004 Dan Walsh 1.15.4-1 +- Latest from Upstream + +* Thu Aug 12 2004 Dan Walsh 1.15.3-2 +- Add man page for boolean functions and SELinux + +* Sun Aug 8 2004 Dan Walsh 1.15.3-1 +- Latest from NSA + +* Mon Jul 19 2004 Dan Walsh 1.15.2-1 +- Latest from NSA + +* Mon Jul 19 2004 Dan Walsh 1.15.1-3 +- uppercase getenforce returns, to make them match system-config-securitylevel + +* Thu Jul 15 2004 Dan Walsh 1.15.1-2 +- Remove old path patch + +* Thu Jul 8 2004 Dan Walsh 1.15.1-1 +- Update to latest from NSA +- Add fix to only get old path if file_context file exists in old location + +* Wed Jun 30 2004 Dan Walsh 1.14.1-1 +- Update to latest from NSA + +* Wed Jun 16 2004 Dan Walsh 1.13.4-1 +- add nlclass patch +- Update to latest from NSA + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Sun Jun 13 2004 Dan Walsh 1.13.3-2 +- Fix selinux_config to break once it finds SELINUXTYPE. + +* Fri May 28 2004 Dan Walsh 1.13.2-1 +-Update with latest from NSA + +* Thu May 27 2004 Dan Walsh 1.13.1-1 +- Change to use new policy mechanism + +* Mon May 17 2004 Dan Walsh 1.12-2 +- add man patch + +* Fri May 14 2004 Dan Walsh 1.12-1 +- Update with latest from NSA + +* Wed May 5 2004 Dan Walsh 1.11.4-1 +- Update with latest from NSA + +* Thu Apr 22 2004 Dan Walsh 1.11.3-1 +- Add changes for relaxed policy +- Update to match NSA + +* Thu Apr 15 2004 Dan Walsh 1.11.2-1 +- Add relaxed policy changes + +* Thu Apr 15 2004 Dan Walsh 1.11-4 +- Sync with NSA + +* Thu Apr 15 2004 Dan Walsh 1.11-3 +- Remove requires glibc>2.3.4 + +* Wed Apr 14 2004 Dan Walsh 1.11-2 +- Fix selinuxenabled man page. + +* Wed Apr 7 2004 Dan Walsh 1.11-1 +- Upgrade to 1.11 + +* Wed Apr 7 2004 Dan Walsh 1.10-2 +- Add memleaks patch + +* Wed Apr 7 2004 Dan Walsh 1.10-1 +- Upgrade to latest from NSA and add more man pages + +* Thu Apr 1 2004 Dan Walsh 1.9-1 +- Update to match NSA +- Cleanup some man pages + +* Tue Mar 30 2004 Dan Walsh 1.8-1 +- Upgrade to latest from NSA + +* Thu Mar 25 2004 Dan Walsh 1.6-6 +- Add Russell's Man pages + +* Thu Mar 25 2004 Dan Walsh 1.6-5 +- Change getenforce to also check is_selinux_enabled + +* Thu Mar 25 2004 Dan Walsh 1.6-4 +- Add ownership to /usr/include/selinux + +* Wed Mar 10 2004 Dan Walsh 1.6-3 +- fix location of file_contexts file. + +* Wed Mar 10 2004 Dan Walsh 1.6-2 +- Fix matchpathcon to use BUFSIZ + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Mon Feb 23 2004 Dan Walsh 1.4-11 +- add matchpathcon + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Fri Jan 23 2004 Dan Walsh 1.4-9 +- Add rootok patch + +* Wed Jan 14 2004 Dan Walsh 1.4-8 +- Updated getpeernam patch + +* Tue Jan 13 2004 Dan Walsh 1.4-7 +- Add getpeernam patch + +* Thu Dec 18 2003 Dan Walsh 1.4-6 +- Add getpeercon patch + +* Thu Dec 18 2003 Dan Walsh 1.4-5 +- Put mntpoint patch, because found fix for SysVinit + +* Wed Dec 17 2003 Dan Walsh 1.4-4 +- Add remove mntpoint patch, because it breaks SysVinit + +* Wed Dec 17 2003 Dan Walsh 1.4-3 +- Add mntpoint patch for SysVinit + +* Fri Dec 12 2003 Dan Walsh 1.4-2 +- Add -r -u -t to getcon + +* Sat Dec 6 2003 Dan Walsh 1.4-1 +- Upgrade to latest from NSA + +* Mon Oct 27 2003 Dan Walsh 1.3-2 +- Fix x86_64 build + +* Wed Oct 22 2003 Dan Walsh 1.3-1 +- Latest tarball from NSA. + +* Tue Oct 21 2003 Dan Walsh 1.2-9 +- Update with latest changes from NSA + +* Mon Oct 20 2003 Dan Walsh 1.2-8 +- Change location of .so file + +* Wed Oct 8 2003 Dan Walsh 1.2-7 +- Break out into development library + +* Wed Oct 8 2003 Dan Walsh 1.2-6 +- Move location of libselinux.so to /lib + +* Fri Oct 3 2003 Dan Walsh 1.2-5 +- Add selinuxenabled patch + +* Wed Oct 1 2003 Dan Walsh 1.2-4 +- Update with final NSA 1.2 sources. + +* Fri Sep 12 2003 Dan Walsh 1.2-3 +- Update with latest from NSA. + +* Thu Aug 28 2003 Dan Walsh 1.2-2 +- Fix to build on x86_64 + +* Thu Aug 21 2003 Dan Walsh 1.2-1 +- update for version 1.2 + +* Tue May 27 2003 Dan Walsh 1.0-1 +- Initial version diff --git a/SPECS/selinuxconlist.8 b/SPECS/selinuxconlist.8 new file mode 100644 index 0000000..c698daa --- /dev/null +++ b/SPECS/selinuxconlist.8 @@ -0,0 +1,18 @@ +.TH "selinuxconlist" "1" "7 May 2008" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxconlist \- list all SELinux context reachable for user +.SH "SYNOPSIS" +.B selinuxconlist [-l level] user [context] + +.SH "DESCRIPTION" +.B selinuxconlist +reports the list of context reachable for user from the current context or specified context + +.B \-l level +mcs/mls level + +.SH AUTHOR +This manual page was written by Dan Walsh . + +.SH "SEE ALSO" +secon(8), selinuxdefcon(8) diff --git a/SPECS/selinuxdefcon.8 b/SPECS/selinuxdefcon.8 new file mode 100644 index 0000000..3cbeff2 --- /dev/null +++ b/SPECS/selinuxdefcon.8 @@ -0,0 +1,24 @@ +.TH "selinuxdefcon" "1" "7 May 2008" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxdefcon \- report default SELinux context for user + +.SH "SYNOPSIS" +.B selinuxdefcon [-l level] user fromcon + +.SH "DESCRIPTION" +.B selinuxdefcon +reports the default context for the specified user from the specified context + +.B \-l level +mcs/mls level + +.SH EXAMPLE +# selinuxdefcon jsmith system_u:system_r:sshd_t:s0 +.br +unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 + +.SH AUTHOR +This manual page was written by Dan Walsh . + +.SH "SEE ALSO" +secon(8), selinuxconlist(8) diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..8c26915 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2.9 diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..8ab9ce9 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,18 @@ +# Installation directories. +PREFIX ?= /usr +INCDIR = $(PREFIX)/include/selinux + +all: + +install: all + test -d $(DESTDIR)$(INCDIR) || install -m 755 -d $(DESTDIR)$(INCDIR) + install -m 644 $(wildcard selinux/*.h) $(DESTDIR)$(INCDIR) + +relabel: + +indent: + ../../scripts/Lindent $(wildcard selinux/*.h) + +distclean clean: + -rm -f selinux/*~ + diff --git a/include/selinux/av_permissions.h b/include/selinux/av_permissions.h new file mode 100644 index 0000000..631f027 --- /dev/null +++ b/include/selinux/av_permissions.h @@ -0,0 +1,1031 @@ +#warning "Please remove any #include of this header in your source code." +#warning "Instead, use string_to_av_perm() to map the permission name to a value." + +/* This file is automatically generated. Do not edit. */ +#define COMMON_FILE__IOCTL 0x00000001UL +#define COMMON_FILE__READ 0x00000002UL +#define COMMON_FILE__WRITE 0x00000004UL +#define COMMON_FILE__CREATE 0x00000008UL +#define COMMON_FILE__GETATTR 0x00000010UL +#define COMMON_FILE__SETATTR 0x00000020UL +#define COMMON_FILE__LOCK 0x00000040UL +#define COMMON_FILE__RELABELFROM 0x00000080UL +#define COMMON_FILE__RELABELTO 0x00000100UL +#define COMMON_FILE__APPEND 0x00000200UL +#define COMMON_FILE__UNLINK 0x00000400UL +#define COMMON_FILE__LINK 0x00000800UL +#define COMMON_FILE__RENAME 0x00001000UL +#define COMMON_FILE__EXECUTE 0x00002000UL +#define COMMON_FILE__SWAPON 0x00004000UL +#define COMMON_FILE__QUOTAON 0x00008000UL +#define COMMON_FILE__MOUNTON 0x00010000UL +#define COMMON_SOCKET__IOCTL 0x00000001UL +#define COMMON_SOCKET__READ 0x00000002UL +#define COMMON_SOCKET__WRITE 0x00000004UL +#define COMMON_SOCKET__CREATE 0x00000008UL +#define COMMON_SOCKET__GETATTR 0x00000010UL +#define COMMON_SOCKET__SETATTR 0x00000020UL +#define COMMON_SOCKET__LOCK 0x00000040UL +#define COMMON_SOCKET__RELABELFROM 0x00000080UL +#define COMMON_SOCKET__RELABELTO 0x00000100UL +#define COMMON_SOCKET__APPEND 0x00000200UL +#define COMMON_SOCKET__BIND 0x00000400UL +#define COMMON_SOCKET__CONNECT 0x00000800UL +#define COMMON_SOCKET__LISTEN 0x00001000UL +#define COMMON_SOCKET__ACCEPT 0x00002000UL +#define COMMON_SOCKET__GETOPT 0x00004000UL +#define COMMON_SOCKET__SETOPT 0x00008000UL +#define COMMON_SOCKET__SHUTDOWN 0x00010000UL +#define COMMON_SOCKET__RECVFROM 0x00020000UL +#define COMMON_SOCKET__SENDTO 0x00040000UL +#define COMMON_SOCKET__RECV_MSG 0x00080000UL +#define COMMON_SOCKET__SEND_MSG 0x00100000UL +#define COMMON_SOCKET__NAME_BIND 0x00200000UL +#define COMMON_IPC__CREATE 0x00000001UL +#define COMMON_IPC__DESTROY 0x00000002UL +#define COMMON_IPC__GETATTR 0x00000004UL +#define COMMON_IPC__SETATTR 0x00000008UL +#define COMMON_IPC__READ 0x00000010UL +#define COMMON_IPC__WRITE 0x00000020UL +#define COMMON_IPC__ASSOCIATE 0x00000040UL +#define COMMON_IPC__UNIX_READ 0x00000080UL +#define COMMON_IPC__UNIX_WRITE 0x00000100UL +#define COMMON_DATABASE__CREATE 0x00000001UL +#define COMMON_DATABASE__DROP 0x00000002UL +#define COMMON_DATABASE__GETATTR 0x00000004UL +#define COMMON_DATABASE__SETATTR 0x00000008UL +#define COMMON_DATABASE__RELABELFROM 0x00000010UL +#define COMMON_DATABASE__RELABELTO 0x00000020UL +#define FILESYSTEM__MOUNT 0x00000001UL +#define FILESYSTEM__REMOUNT 0x00000002UL +#define FILESYSTEM__UNMOUNT 0x00000004UL +#define FILESYSTEM__GETATTR 0x00000008UL +#define FILESYSTEM__RELABELFROM 0x00000010UL +#define FILESYSTEM__RELABELTO 0x00000020UL +#define FILESYSTEM__TRANSITION 0x00000040UL +#define FILESYSTEM__ASSOCIATE 0x00000080UL +#define FILESYSTEM__QUOTAMOD 0x00000100UL +#define FILESYSTEM__QUOTAGET 0x00000200UL +#define DIR__IOCTL 0x00000001UL +#define DIR__READ 0x00000002UL +#define DIR__WRITE 0x00000004UL +#define DIR__CREATE 0x00000008UL +#define DIR__GETATTR 0x00000010UL +#define DIR__SETATTR 0x00000020UL +#define DIR__LOCK 0x00000040UL +#define DIR__RELABELFROM 0x00000080UL +#define DIR__RELABELTO 0x00000100UL +#define DIR__APPEND 0x00000200UL +#define DIR__UNLINK 0x00000400UL +#define DIR__LINK 0x00000800UL +#define DIR__RENAME 0x00001000UL +#define DIR__EXECUTE 0x00002000UL +#define DIR__SWAPON 0x00004000UL +#define DIR__QUOTAON 0x00008000UL +#define DIR__MOUNTON 0x00010000UL +#define DIR__ADD_NAME 0x00020000UL +#define DIR__REMOVE_NAME 0x00040000UL +#define DIR__REPARENT 0x00080000UL +#define DIR__SEARCH 0x00100000UL +#define DIR__RMDIR 0x00200000UL +#define DIR__OPEN 0x00400000UL +#define FILE__IOCTL 0x00000001UL +#define FILE__READ 0x00000002UL +#define FILE__WRITE 0x00000004UL +#define FILE__CREATE 0x00000008UL +#define FILE__GETATTR 0x00000010UL +#define FILE__SETATTR 0x00000020UL +#define FILE__LOCK 0x00000040UL +#define FILE__RELABELFROM 0x00000080UL +#define FILE__RELABELTO 0x00000100UL +#define FILE__APPEND 0x00000200UL +#define FILE__UNLINK 0x00000400UL +#define FILE__LINK 0x00000800UL +#define FILE__RENAME 0x00001000UL +#define FILE__EXECUTE 0x00002000UL +#define FILE__SWAPON 0x00004000UL +#define FILE__QUOTAON 0x00008000UL +#define FILE__MOUNTON 0x00010000UL +#define FILE__EXECUTE_NO_TRANS 0x00020000UL +#define FILE__ENTRYPOINT 0x00040000UL +#define FILE__EXECMOD 0x00080000UL +#define FILE__OPEN 0x00100000UL +#define LNK_FILE__IOCTL 0x00000001UL +#define LNK_FILE__READ 0x00000002UL +#define LNK_FILE__WRITE 0x00000004UL +#define LNK_FILE__CREATE 0x00000008UL +#define LNK_FILE__GETATTR 0x00000010UL +#define LNK_FILE__SETATTR 0x00000020UL +#define LNK_FILE__LOCK 0x00000040UL +#define LNK_FILE__RELABELFROM 0x00000080UL +#define LNK_FILE__RELABELTO 0x00000100UL +#define LNK_FILE__APPEND 0x00000200UL +#define LNK_FILE__UNLINK 0x00000400UL +#define LNK_FILE__LINK 0x00000800UL +#define LNK_FILE__RENAME 0x00001000UL +#define LNK_FILE__EXECUTE 0x00002000UL +#define LNK_FILE__SWAPON 0x00004000UL +#define LNK_FILE__QUOTAON 0x00008000UL +#define LNK_FILE__MOUNTON 0x00010000UL +#define CHR_FILE__IOCTL 0x00000001UL +#define CHR_FILE__READ 0x00000002UL +#define CHR_FILE__WRITE 0x00000004UL +#define CHR_FILE__CREATE 0x00000008UL +#define CHR_FILE__GETATTR 0x00000010UL +#define CHR_FILE__SETATTR 0x00000020UL +#define CHR_FILE__LOCK 0x00000040UL +#define CHR_FILE__RELABELFROM 0x00000080UL +#define CHR_FILE__RELABELTO 0x00000100UL +#define CHR_FILE__APPEND 0x00000200UL +#define CHR_FILE__UNLINK 0x00000400UL +#define CHR_FILE__LINK 0x00000800UL +#define CHR_FILE__RENAME 0x00001000UL +#define CHR_FILE__EXECUTE 0x00002000UL +#define CHR_FILE__SWAPON 0x00004000UL +#define CHR_FILE__QUOTAON 0x00008000UL +#define CHR_FILE__MOUNTON 0x00010000UL +#define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL +#define CHR_FILE__ENTRYPOINT 0x00040000UL +#define CHR_FILE__EXECMOD 0x00080000UL +#define CHR_FILE__OPEN 0x00100000UL +#define BLK_FILE__IOCTL 0x00000001UL +#define BLK_FILE__READ 0x00000002UL +#define BLK_FILE__WRITE 0x00000004UL +#define BLK_FILE__CREATE 0x00000008UL +#define BLK_FILE__GETATTR 0x00000010UL +#define BLK_FILE__SETATTR 0x00000020UL +#define BLK_FILE__LOCK 0x00000040UL +#define BLK_FILE__RELABELFROM 0x00000080UL +#define BLK_FILE__RELABELTO 0x00000100UL +#define BLK_FILE__APPEND 0x00000200UL +#define BLK_FILE__UNLINK 0x00000400UL +#define BLK_FILE__LINK 0x00000800UL +#define BLK_FILE__RENAME 0x00001000UL +#define BLK_FILE__EXECUTE 0x00002000UL +#define BLK_FILE__SWAPON 0x00004000UL +#define BLK_FILE__QUOTAON 0x00008000UL +#define BLK_FILE__MOUNTON 0x00010000UL +#define BLK_FILE__OPEN 0x00020000UL +#define SOCK_FILE__IOCTL 0x00000001UL +#define SOCK_FILE__READ 0x00000002UL +#define SOCK_FILE__WRITE 0x00000004UL +#define SOCK_FILE__CREATE 0x00000008UL +#define SOCK_FILE__GETATTR 0x00000010UL +#define SOCK_FILE__SETATTR 0x00000020UL +#define SOCK_FILE__LOCK 0x00000040UL +#define SOCK_FILE__RELABELFROM 0x00000080UL +#define SOCK_FILE__RELABELTO 0x00000100UL +#define SOCK_FILE__APPEND 0x00000200UL +#define SOCK_FILE__UNLINK 0x00000400UL +#define SOCK_FILE__LINK 0x00000800UL +#define SOCK_FILE__RENAME 0x00001000UL +#define SOCK_FILE__EXECUTE 0x00002000UL +#define SOCK_FILE__SWAPON 0x00004000UL +#define SOCK_FILE__QUOTAON 0x00008000UL +#define SOCK_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__IOCTL 0x00000001UL +#define FIFO_FILE__READ 0x00000002UL +#define FIFO_FILE__WRITE 0x00000004UL +#define FIFO_FILE__CREATE 0x00000008UL +#define FIFO_FILE__GETATTR 0x00000010UL +#define FIFO_FILE__SETATTR 0x00000020UL +#define FIFO_FILE__LOCK 0x00000040UL +#define FIFO_FILE__RELABELFROM 0x00000080UL +#define FIFO_FILE__RELABELTO 0x00000100UL +#define FIFO_FILE__APPEND 0x00000200UL +#define FIFO_FILE__UNLINK 0x00000400UL +#define FIFO_FILE__LINK 0x00000800UL +#define FIFO_FILE__RENAME 0x00001000UL +#define FIFO_FILE__EXECUTE 0x00002000UL +#define FIFO_FILE__SWAPON 0x00004000UL +#define FIFO_FILE__QUOTAON 0x00008000UL +#define FIFO_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__OPEN 0x00020000UL +#define FD__USE 0x00000001UL +#define SOCKET__IOCTL 0x00000001UL +#define SOCKET__READ 0x00000002UL +#define SOCKET__WRITE 0x00000004UL +#define SOCKET__CREATE 0x00000008UL +#define SOCKET__GETATTR 0x00000010UL +#define SOCKET__SETATTR 0x00000020UL +#define SOCKET__LOCK 0x00000040UL +#define SOCKET__RELABELFROM 0x00000080UL +#define SOCKET__RELABELTO 0x00000100UL +#define SOCKET__APPEND 0x00000200UL +#define SOCKET__BIND 0x00000400UL +#define SOCKET__CONNECT 0x00000800UL +#define SOCKET__LISTEN 0x00001000UL +#define SOCKET__ACCEPT 0x00002000UL +#define SOCKET__GETOPT 0x00004000UL +#define SOCKET__SETOPT 0x00008000UL +#define SOCKET__SHUTDOWN 0x00010000UL +#define SOCKET__RECVFROM 0x00020000UL +#define SOCKET__SENDTO 0x00040000UL +#define SOCKET__RECV_MSG 0x00080000UL +#define SOCKET__SEND_MSG 0x00100000UL +#define SOCKET__NAME_BIND 0x00200000UL +#define TCP_SOCKET__IOCTL 0x00000001UL +#define TCP_SOCKET__READ 0x00000002UL +#define TCP_SOCKET__WRITE 0x00000004UL +#define TCP_SOCKET__CREATE 0x00000008UL +#define TCP_SOCKET__GETATTR 0x00000010UL +#define TCP_SOCKET__SETATTR 0x00000020UL +#define TCP_SOCKET__LOCK 0x00000040UL +#define TCP_SOCKET__RELABELFROM 0x00000080UL +#define TCP_SOCKET__RELABELTO 0x00000100UL +#define TCP_SOCKET__APPEND 0x00000200UL +#define TCP_SOCKET__BIND 0x00000400UL +#define TCP_SOCKET__CONNECT 0x00000800UL +#define TCP_SOCKET__LISTEN 0x00001000UL +#define TCP_SOCKET__ACCEPT 0x00002000UL +#define TCP_SOCKET__GETOPT 0x00004000UL +#define TCP_SOCKET__SETOPT 0x00008000UL +#define TCP_SOCKET__SHUTDOWN 0x00010000UL +#define TCP_SOCKET__RECVFROM 0x00020000UL +#define TCP_SOCKET__SENDTO 0x00040000UL +#define TCP_SOCKET__RECV_MSG 0x00080000UL +#define TCP_SOCKET__SEND_MSG 0x00100000UL +#define TCP_SOCKET__NAME_BIND 0x00200000UL +#define TCP_SOCKET__CONNECTTO 0x00400000UL +#define TCP_SOCKET__NEWCONN 0x00800000UL +#define TCP_SOCKET__ACCEPTFROM 0x01000000UL +#define TCP_SOCKET__NODE_BIND 0x02000000UL +#define TCP_SOCKET__NAME_CONNECT 0x04000000UL +#define UDP_SOCKET__IOCTL 0x00000001UL +#define UDP_SOCKET__READ 0x00000002UL +#define UDP_SOCKET__WRITE 0x00000004UL +#define UDP_SOCKET__CREATE 0x00000008UL +#define UDP_SOCKET__GETATTR 0x00000010UL +#define UDP_SOCKET__SETATTR 0x00000020UL +#define UDP_SOCKET__LOCK 0x00000040UL +#define UDP_SOCKET__RELABELFROM 0x00000080UL +#define UDP_SOCKET__RELABELTO 0x00000100UL +#define UDP_SOCKET__APPEND 0x00000200UL +#define UDP_SOCKET__BIND 0x00000400UL +#define UDP_SOCKET__CONNECT 0x00000800UL +#define UDP_SOCKET__LISTEN 0x00001000UL +#define UDP_SOCKET__ACCEPT 0x00002000UL +#define UDP_SOCKET__GETOPT 0x00004000UL +#define UDP_SOCKET__SETOPT 0x00008000UL +#define UDP_SOCKET__SHUTDOWN 0x00010000UL +#define UDP_SOCKET__RECVFROM 0x00020000UL +#define UDP_SOCKET__SENDTO 0x00040000UL +#define UDP_SOCKET__RECV_MSG 0x00080000UL +#define UDP_SOCKET__SEND_MSG 0x00100000UL +#define UDP_SOCKET__NAME_BIND 0x00200000UL +#define UDP_SOCKET__NODE_BIND 0x00400000UL +#define RAWIP_SOCKET__IOCTL 0x00000001UL +#define RAWIP_SOCKET__READ 0x00000002UL +#define RAWIP_SOCKET__WRITE 0x00000004UL +#define RAWIP_SOCKET__CREATE 0x00000008UL +#define RAWIP_SOCKET__GETATTR 0x00000010UL +#define RAWIP_SOCKET__SETATTR 0x00000020UL +#define RAWIP_SOCKET__LOCK 0x00000040UL +#define RAWIP_SOCKET__RELABELFROM 0x00000080UL +#define RAWIP_SOCKET__RELABELTO 0x00000100UL +#define RAWIP_SOCKET__APPEND 0x00000200UL +#define RAWIP_SOCKET__BIND 0x00000400UL +#define RAWIP_SOCKET__CONNECT 0x00000800UL +#define RAWIP_SOCKET__LISTEN 0x00001000UL +#define RAWIP_SOCKET__ACCEPT 0x00002000UL +#define RAWIP_SOCKET__GETOPT 0x00004000UL +#define RAWIP_SOCKET__SETOPT 0x00008000UL +#define RAWIP_SOCKET__SHUTDOWN 0x00010000UL +#define RAWIP_SOCKET__RECVFROM 0x00020000UL +#define RAWIP_SOCKET__SENDTO 0x00040000UL +#define RAWIP_SOCKET__RECV_MSG 0x00080000UL +#define RAWIP_SOCKET__SEND_MSG 0x00100000UL +#define RAWIP_SOCKET__NAME_BIND 0x00200000UL +#define RAWIP_SOCKET__NODE_BIND 0x00400000UL +#define NODE__TCP_RECV 0x00000001UL +#define NODE__TCP_SEND 0x00000002UL +#define NODE__UDP_RECV 0x00000004UL +#define NODE__UDP_SEND 0x00000008UL +#define NODE__RAWIP_RECV 0x00000010UL +#define NODE__RAWIP_SEND 0x00000020UL +#define NODE__ENFORCE_DEST 0x00000040UL +#define NODE__DCCP_RECV 0x00000080UL +#define NODE__DCCP_SEND 0x00000100UL +#define NODE__RECVFROM 0x00000200UL +#define NODE__SENDTO 0x00000400UL +#define NETIF__TCP_RECV 0x00000001UL +#define NETIF__TCP_SEND 0x00000002UL +#define NETIF__UDP_RECV 0x00000004UL +#define NETIF__UDP_SEND 0x00000008UL +#define NETIF__RAWIP_RECV 0x00000010UL +#define NETIF__RAWIP_SEND 0x00000020UL +#define NETIF__DCCP_RECV 0x00000040UL +#define NETIF__DCCP_SEND 0x00000080UL +#define NETIF__INGRESS 0x00000100UL +#define NETIF__EGRESS 0x00000200UL +#define NETLINK_SOCKET__IOCTL 0x00000001UL +#define NETLINK_SOCKET__READ 0x00000002UL +#define NETLINK_SOCKET__WRITE 0x00000004UL +#define NETLINK_SOCKET__CREATE 0x00000008UL +#define NETLINK_SOCKET__GETATTR 0x00000010UL +#define NETLINK_SOCKET__SETATTR 0x00000020UL +#define NETLINK_SOCKET__LOCK 0x00000040UL +#define NETLINK_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_SOCKET__APPEND 0x00000200UL +#define NETLINK_SOCKET__BIND 0x00000400UL +#define NETLINK_SOCKET__CONNECT 0x00000800UL +#define NETLINK_SOCKET__LISTEN 0x00001000UL +#define NETLINK_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_SOCKET__GETOPT 0x00004000UL +#define NETLINK_SOCKET__SETOPT 0x00008000UL +#define NETLINK_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_SOCKET__SENDTO 0x00040000UL +#define NETLINK_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_SOCKET__NAME_BIND 0x00200000UL +#define PACKET_SOCKET__IOCTL 0x00000001UL +#define PACKET_SOCKET__READ 0x00000002UL +#define PACKET_SOCKET__WRITE 0x00000004UL +#define PACKET_SOCKET__CREATE 0x00000008UL +#define PACKET_SOCKET__GETATTR 0x00000010UL +#define PACKET_SOCKET__SETATTR 0x00000020UL +#define PACKET_SOCKET__LOCK 0x00000040UL +#define PACKET_SOCKET__RELABELFROM 0x00000080UL +#define PACKET_SOCKET__RELABELTO 0x00000100UL +#define PACKET_SOCKET__APPEND 0x00000200UL +#define PACKET_SOCKET__BIND 0x00000400UL +#define PACKET_SOCKET__CONNECT 0x00000800UL +#define PACKET_SOCKET__LISTEN 0x00001000UL +#define PACKET_SOCKET__ACCEPT 0x00002000UL +#define PACKET_SOCKET__GETOPT 0x00004000UL +#define PACKET_SOCKET__SETOPT 0x00008000UL +#define PACKET_SOCKET__SHUTDOWN 0x00010000UL +#define PACKET_SOCKET__RECVFROM 0x00020000UL +#define PACKET_SOCKET__SENDTO 0x00040000UL +#define PACKET_SOCKET__RECV_MSG 0x00080000UL +#define PACKET_SOCKET__SEND_MSG 0x00100000UL +#define PACKET_SOCKET__NAME_BIND 0x00200000UL +#define KEY_SOCKET__IOCTL 0x00000001UL +#define KEY_SOCKET__READ 0x00000002UL +#define KEY_SOCKET__WRITE 0x00000004UL +#define KEY_SOCKET__CREATE 0x00000008UL +#define KEY_SOCKET__GETATTR 0x00000010UL +#define KEY_SOCKET__SETATTR 0x00000020UL +#define KEY_SOCKET__LOCK 0x00000040UL +#define KEY_SOCKET__RELABELFROM 0x00000080UL +#define KEY_SOCKET__RELABELTO 0x00000100UL +#define KEY_SOCKET__APPEND 0x00000200UL +#define KEY_SOCKET__BIND 0x00000400UL +#define KEY_SOCKET__CONNECT 0x00000800UL +#define KEY_SOCKET__LISTEN 0x00001000UL +#define KEY_SOCKET__ACCEPT 0x00002000UL +#define KEY_SOCKET__GETOPT 0x00004000UL +#define KEY_SOCKET__SETOPT 0x00008000UL +#define KEY_SOCKET__SHUTDOWN 0x00010000UL +#define KEY_SOCKET__RECVFROM 0x00020000UL +#define KEY_SOCKET__SENDTO 0x00040000UL +#define KEY_SOCKET__RECV_MSG 0x00080000UL +#define KEY_SOCKET__SEND_MSG 0x00100000UL +#define KEY_SOCKET__NAME_BIND 0x00200000UL +#define UNIX_STREAM_SOCKET__IOCTL 0x00000001UL +#define UNIX_STREAM_SOCKET__READ 0x00000002UL +#define UNIX_STREAM_SOCKET__WRITE 0x00000004UL +#define UNIX_STREAM_SOCKET__CREATE 0x00000008UL +#define UNIX_STREAM_SOCKET__GETATTR 0x00000010UL +#define UNIX_STREAM_SOCKET__SETATTR 0x00000020UL +#define UNIX_STREAM_SOCKET__LOCK 0x00000040UL +#define UNIX_STREAM_SOCKET__RELABELFROM 0x00000080UL +#define UNIX_STREAM_SOCKET__RELABELTO 0x00000100UL +#define UNIX_STREAM_SOCKET__APPEND 0x00000200UL +#define UNIX_STREAM_SOCKET__BIND 0x00000400UL +#define UNIX_STREAM_SOCKET__CONNECT 0x00000800UL +#define UNIX_STREAM_SOCKET__LISTEN 0x00001000UL +#define UNIX_STREAM_SOCKET__ACCEPT 0x00002000UL +#define UNIX_STREAM_SOCKET__GETOPT 0x00004000UL +#define UNIX_STREAM_SOCKET__SETOPT 0x00008000UL +#define UNIX_STREAM_SOCKET__SHUTDOWN 0x00010000UL +#define UNIX_STREAM_SOCKET__RECVFROM 0x00020000UL +#define UNIX_STREAM_SOCKET__SENDTO 0x00040000UL +#define UNIX_STREAM_SOCKET__RECV_MSG 0x00080000UL +#define UNIX_STREAM_SOCKET__SEND_MSG 0x00100000UL +#define UNIX_STREAM_SOCKET__NAME_BIND 0x00200000UL +#define UNIX_STREAM_SOCKET__CONNECTTO 0x00400000UL +#define UNIX_STREAM_SOCKET__NEWCONN 0x00800000UL +#define UNIX_STREAM_SOCKET__ACCEPTFROM 0x01000000UL +#define UNIX_DGRAM_SOCKET__IOCTL 0x00000001UL +#define UNIX_DGRAM_SOCKET__READ 0x00000002UL +#define UNIX_DGRAM_SOCKET__WRITE 0x00000004UL +#define UNIX_DGRAM_SOCKET__CREATE 0x00000008UL +#define UNIX_DGRAM_SOCKET__GETATTR 0x00000010UL +#define UNIX_DGRAM_SOCKET__SETATTR 0x00000020UL +#define UNIX_DGRAM_SOCKET__LOCK 0x00000040UL +#define UNIX_DGRAM_SOCKET__RELABELFROM 0x00000080UL +#define UNIX_DGRAM_SOCKET__RELABELTO 0x00000100UL +#define UNIX_DGRAM_SOCKET__APPEND 0x00000200UL +#define UNIX_DGRAM_SOCKET__BIND 0x00000400UL +#define UNIX_DGRAM_SOCKET__CONNECT 0x00000800UL +#define UNIX_DGRAM_SOCKET__LISTEN 0x00001000UL +#define UNIX_DGRAM_SOCKET__ACCEPT 0x00002000UL +#define UNIX_DGRAM_SOCKET__GETOPT 0x00004000UL +#define UNIX_DGRAM_SOCKET__SETOPT 0x00008000UL +#define UNIX_DGRAM_SOCKET__SHUTDOWN 0x00010000UL +#define UNIX_DGRAM_SOCKET__RECVFROM 0x00020000UL +#define UNIX_DGRAM_SOCKET__SENDTO 0x00040000UL +#define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL +#define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL +#define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL +#define PROCESS__FORK 0x00000001UL +#define PROCESS__TRANSITION 0x00000002UL +#define PROCESS__SIGCHLD 0x00000004UL +#define PROCESS__SIGKILL 0x00000008UL +#define PROCESS__SIGSTOP 0x00000010UL +#define PROCESS__SIGNULL 0x00000020UL +#define PROCESS__SIGNAL 0x00000040UL +#define PROCESS__PTRACE 0x00000080UL +#define PROCESS__GETSCHED 0x00000100UL +#define PROCESS__SETSCHED 0x00000200UL +#define PROCESS__GETSESSION 0x00000400UL +#define PROCESS__GETPGID 0x00000800UL +#define PROCESS__SETPGID 0x00001000UL +#define PROCESS__GETCAP 0x00002000UL +#define PROCESS__SETCAP 0x00004000UL +#define PROCESS__SHARE 0x00008000UL +#define PROCESS__GETATTR 0x00010000UL +#define PROCESS__SETEXEC 0x00020000UL +#define PROCESS__SETFSCREATE 0x00040000UL +#define PROCESS__NOATSECURE 0x00080000UL +#define PROCESS__SIGINH 0x00100000UL +#define PROCESS__SETRLIMIT 0x00200000UL +#define PROCESS__RLIMITINH 0x00400000UL +#define PROCESS__DYNTRANSITION 0x00800000UL +#define PROCESS__SETCURRENT 0x01000000UL +#define PROCESS__EXECMEM 0x02000000UL +#define PROCESS__EXECSTACK 0x04000000UL +#define PROCESS__EXECHEAP 0x08000000UL +#define PROCESS__SETKEYCREATE 0x10000000UL +#define PROCESS__SETSOCKCREATE 0x20000000UL +#define IPC__CREATE 0x00000001UL +#define IPC__DESTROY 0x00000002UL +#define IPC__GETATTR 0x00000004UL +#define IPC__SETATTR 0x00000008UL +#define IPC__READ 0x00000010UL +#define IPC__WRITE 0x00000020UL +#define IPC__ASSOCIATE 0x00000040UL +#define IPC__UNIX_READ 0x00000080UL +#define IPC__UNIX_WRITE 0x00000100UL +#define SEM__CREATE 0x00000001UL +#define SEM__DESTROY 0x00000002UL +#define SEM__GETATTR 0x00000004UL +#define SEM__SETATTR 0x00000008UL +#define SEM__READ 0x00000010UL +#define SEM__WRITE 0x00000020UL +#define SEM__ASSOCIATE 0x00000040UL +#define SEM__UNIX_READ 0x00000080UL +#define SEM__UNIX_WRITE 0x00000100UL +#define MSGQ__CREATE 0x00000001UL +#define MSGQ__DESTROY 0x00000002UL +#define MSGQ__GETATTR 0x00000004UL +#define MSGQ__SETATTR 0x00000008UL +#define MSGQ__READ 0x00000010UL +#define MSGQ__WRITE 0x00000020UL +#define MSGQ__ASSOCIATE 0x00000040UL +#define MSGQ__UNIX_READ 0x00000080UL +#define MSGQ__UNIX_WRITE 0x00000100UL +#define MSGQ__ENQUEUE 0x00000200UL +#define MSG__SEND 0x00000001UL +#define MSG__RECEIVE 0x00000002UL +#define SHM__CREATE 0x00000001UL +#define SHM__DESTROY 0x00000002UL +#define SHM__GETATTR 0x00000004UL +#define SHM__SETATTR 0x00000008UL +#define SHM__READ 0x00000010UL +#define SHM__WRITE 0x00000020UL +#define SHM__ASSOCIATE 0x00000040UL +#define SHM__UNIX_READ 0x00000080UL +#define SHM__UNIX_WRITE 0x00000100UL +#define SHM__LOCK 0x00000200UL +#define SECURITY__COMPUTE_AV 0x00000001UL +#define SECURITY__COMPUTE_CREATE 0x00000002UL +#define SECURITY__COMPUTE_MEMBER 0x00000004UL +#define SECURITY__CHECK_CONTEXT 0x00000008UL +#define SECURITY__LOAD_POLICY 0x00000010UL +#define SECURITY__COMPUTE_RELABEL 0x00000020UL +#define SECURITY__COMPUTE_USER 0x00000040UL +#define SECURITY__SETENFORCE 0x00000080UL +#define SECURITY__SETBOOL 0x00000100UL +#define SECURITY__SETSECPARAM 0x00000200UL +#define SECURITY__SETCHECKREQPROT 0x00000400UL +#define SYSTEM__IPC_INFO 0x00000001UL +#define SYSTEM__SYSLOG_READ 0x00000002UL +#define SYSTEM__SYSLOG_MOD 0x00000004UL +#define SYSTEM__SYSLOG_CONSOLE 0x00000008UL +#define CAPABILITY__CHOWN 0x00000001UL +#define CAPABILITY__DAC_OVERRIDE 0x00000002UL +#define CAPABILITY__DAC_READ_SEARCH 0x00000004UL +#define CAPABILITY__FOWNER 0x00000008UL +#define CAPABILITY__FSETID 0x00000010UL +#define CAPABILITY__KILL 0x00000020UL +#define CAPABILITY__SETGID 0x00000040UL +#define CAPABILITY__SETUID 0x00000080UL +#define CAPABILITY__SETPCAP 0x00000100UL +#define CAPABILITY__LINUX_IMMUTABLE 0x00000200UL +#define CAPABILITY__NET_BIND_SERVICE 0x00000400UL +#define CAPABILITY__NET_BROADCAST 0x00000800UL +#define CAPABILITY__NET_ADMIN 0x00001000UL +#define CAPABILITY__NET_RAW 0x00002000UL +#define CAPABILITY__IPC_LOCK 0x00004000UL +#define CAPABILITY__IPC_OWNER 0x00008000UL +#define CAPABILITY__SYS_MODULE 0x00010000UL +#define CAPABILITY__SYS_RAWIO 0x00020000UL +#define CAPABILITY__SYS_CHROOT 0x00040000UL +#define CAPABILITY__SYS_PTRACE 0x00080000UL +#define CAPABILITY__SYS_PACCT 0x00100000UL +#define CAPABILITY__SYS_ADMIN 0x00200000UL +#define CAPABILITY__SYS_BOOT 0x00400000UL +#define CAPABILITY__SYS_NICE 0x00800000UL +#define CAPABILITY__SYS_RESOURCE 0x01000000UL +#define CAPABILITY__SYS_TIME 0x02000000UL +#define CAPABILITY__SYS_TTY_CONFIG 0x04000000UL +#define CAPABILITY__MKNOD 0x08000000UL +#define CAPABILITY__LEASE 0x10000000UL +#define CAPABILITY__AUDIT_WRITE 0x20000000UL +#define CAPABILITY__AUDIT_CONTROL 0x40000000UL +#define CAPABILITY__SETFCAP 0x80000000UL +#define CAPABILITY2__MAC_OVERRIDE 0x00000001UL +#define CAPABILITY2__MAC_ADMIN 0x00000002UL +#define PASSWD__PASSWD 0x00000001UL +#define PASSWD__CHFN 0x00000002UL +#define PASSWD__CHSH 0x00000004UL +#define PASSWD__ROOTOK 0x00000008UL +#define PASSWD__CRONTAB 0x00000010UL +#define X_DRAWABLE__CREATE 0x00000001UL +#define X_DRAWABLE__DESTROY 0x00000002UL +#define X_DRAWABLE__READ 0x00000004UL +#define X_DRAWABLE__WRITE 0x00000008UL +#define X_DRAWABLE__BLEND 0x00000010UL +#define X_DRAWABLE__GETATTR 0x00000020UL +#define X_DRAWABLE__SETATTR 0x00000040UL +#define X_DRAWABLE__LIST_CHILD 0x00000080UL +#define X_DRAWABLE__ADD_CHILD 0x00000100UL +#define X_DRAWABLE__REMOVE_CHILD 0x00000200UL +#define X_DRAWABLE__LIST_PROPERTY 0x00000400UL +#define X_DRAWABLE__GET_PROPERTY 0x00000800UL +#define X_DRAWABLE__SET_PROPERTY 0x00001000UL +#define X_DRAWABLE__MANAGE 0x00002000UL +#define X_DRAWABLE__OVERRIDE 0x00004000UL +#define X_DRAWABLE__SHOW 0x00008000UL +#define X_DRAWABLE__HIDE 0x00010000UL +#define X_DRAWABLE__SEND 0x00020000UL +#define X_DRAWABLE__RECEIVE 0x00040000UL +#define X_SCREEN__GETATTR 0x00000001UL +#define X_SCREEN__SETATTR 0x00000002UL +#define X_SCREEN__HIDE_CURSOR 0x00000004UL +#define X_SCREEN__SHOW_CURSOR 0x00000008UL +#define X_SCREEN__SAVER_GETATTR 0x00000010UL +#define X_SCREEN__SAVER_SETATTR 0x00000020UL +#define X_SCREEN__SAVER_HIDE 0x00000040UL +#define X_SCREEN__SAVER_SHOW 0x00000080UL +#define X_GC__CREATE 0x00000001UL +#define X_GC__DESTROY 0x00000002UL +#define X_GC__GETATTR 0x00000004UL +#define X_GC__SETATTR 0x00000008UL +#define X_GC__USE 0x00000010UL +#define X_FONT__CREATE 0x00000001UL +#define X_FONT__DESTROY 0x00000002UL +#define X_FONT__GETATTR 0x00000004UL +#define X_FONT__ADD_GLYPH 0x00000008UL +#define X_FONT__REMOVE_GLYPH 0x00000010UL +#define X_FONT__USE 0x00000020UL +#define X_COLORMAP__CREATE 0x00000001UL +#define X_COLORMAP__DESTROY 0x00000002UL +#define X_COLORMAP__READ 0x00000004UL +#define X_COLORMAP__WRITE 0x00000008UL +#define X_COLORMAP__GETATTR 0x00000010UL +#define X_COLORMAP__ADD_COLOR 0x00000020UL +#define X_COLORMAP__REMOVE_COLOR 0x00000040UL +#define X_COLORMAP__INSTALL 0x00000080UL +#define X_COLORMAP__UNINSTALL 0x00000100UL +#define X_COLORMAP__USE 0x00000200UL +#define X_PROPERTY__CREATE 0x00000001UL +#define X_PROPERTY__DESTROY 0x00000002UL +#define X_PROPERTY__READ 0x00000004UL +#define X_PROPERTY__WRITE 0x00000008UL +#define X_PROPERTY__APPEND 0x00000010UL +#define X_PROPERTY__GETATTR 0x00000020UL +#define X_PROPERTY__SETATTR 0x00000040UL +#define X_SELECTION__READ 0x00000001UL +#define X_SELECTION__WRITE 0x00000002UL +#define X_SELECTION__GETATTR 0x00000004UL +#define X_SELECTION__SETATTR 0x00000008UL +#define X_CURSOR__CREATE 0x00000001UL +#define X_CURSOR__DESTROY 0x00000002UL +#define X_CURSOR__READ 0x00000004UL +#define X_CURSOR__WRITE 0x00000008UL +#define X_CURSOR__GETATTR 0x00000010UL +#define X_CURSOR__SETATTR 0x00000020UL +#define X_CURSOR__USE 0x00000040UL +#define X_CLIENT__DESTROY 0x00000001UL +#define X_CLIENT__GETATTR 0x00000002UL +#define X_CLIENT__SETATTR 0x00000004UL +#define X_CLIENT__MANAGE 0x00000008UL +#define X_DEVICE__GETATTR 0x00000001UL +#define X_DEVICE__SETATTR 0x00000002UL +#define X_DEVICE__USE 0x00000004UL +#define X_DEVICE__READ 0x00000008UL +#define X_DEVICE__WRITE 0x00000010UL +#define X_DEVICE__GETFOCUS 0x00000020UL +#define X_DEVICE__SETFOCUS 0x00000040UL +#define X_DEVICE__BELL 0x00000080UL +#define X_DEVICE__FORCE_CURSOR 0x00000100UL +#define X_DEVICE__FREEZE 0x00000200UL +#define X_DEVICE__GRAB 0x00000400UL +#define X_DEVICE__MANAGE 0x00000800UL +#define X_SERVER__GETATTR 0x00000001UL +#define X_SERVER__SETATTR 0x00000002UL +#define X_SERVER__RECORD 0x00000004UL +#define X_SERVER__DEBUG 0x00000008UL +#define X_SERVER__GRAB 0x00000010UL +#define X_SERVER__MANAGE 0x00000020UL +#define X_EXTENSION__QUERY 0x00000001UL +#define X_EXTENSION__USE 0x00000002UL +#define X_RESOURCE__READ 0x00000001UL +#define X_RESOURCE__WRITE 0x00000002UL +#define X_EVENT__SEND 0x00000001UL +#define X_EVENT__RECEIVE 0x00000002UL +#define X_SYNTHETIC_EVENT__SEND 0x00000001UL +#define X_SYNTHETIC_EVENT__RECEIVE 0x00000002UL +#define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL +#define NETLINK_ROUTE_SOCKET__READ 0x00000002UL +#define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL +#define NETLINK_ROUTE_SOCKET__CREATE 0x00000008UL +#define NETLINK_ROUTE_SOCKET__GETATTR 0x00000010UL +#define NETLINK_ROUTE_SOCKET__SETATTR 0x00000020UL +#define NETLINK_ROUTE_SOCKET__LOCK 0x00000040UL +#define NETLINK_ROUTE_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_ROUTE_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_ROUTE_SOCKET__APPEND 0x00000200UL +#define NETLINK_ROUTE_SOCKET__BIND 0x00000400UL +#define NETLINK_ROUTE_SOCKET__CONNECT 0x00000800UL +#define NETLINK_ROUTE_SOCKET__LISTEN 0x00001000UL +#define NETLINK_ROUTE_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_ROUTE_SOCKET__GETOPT 0x00004000UL +#define NETLINK_ROUTE_SOCKET__SETOPT 0x00008000UL +#define NETLINK_ROUTE_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_ROUTE_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_ROUTE_SOCKET__SENDTO 0x00040000UL +#define NETLINK_ROUTE_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_ROUTE_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_ROUTE_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_ROUTE_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_ROUTE_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_FIREWALL_SOCKET__IOCTL 0x00000001UL +#define NETLINK_FIREWALL_SOCKET__READ 0x00000002UL +#define NETLINK_FIREWALL_SOCKET__WRITE 0x00000004UL +#define NETLINK_FIREWALL_SOCKET__CREATE 0x00000008UL +#define NETLINK_FIREWALL_SOCKET__GETATTR 0x00000010UL +#define NETLINK_FIREWALL_SOCKET__SETATTR 0x00000020UL +#define NETLINK_FIREWALL_SOCKET__LOCK 0x00000040UL +#define NETLINK_FIREWALL_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_FIREWALL_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_FIREWALL_SOCKET__APPEND 0x00000200UL +#define NETLINK_FIREWALL_SOCKET__BIND 0x00000400UL +#define NETLINK_FIREWALL_SOCKET__CONNECT 0x00000800UL +#define NETLINK_FIREWALL_SOCKET__LISTEN 0x00001000UL +#define NETLINK_FIREWALL_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_FIREWALL_SOCKET__GETOPT 0x00004000UL +#define NETLINK_FIREWALL_SOCKET__SETOPT 0x00008000UL +#define NETLINK_FIREWALL_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_FIREWALL_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_FIREWALL_SOCKET__SENDTO 0x00040000UL +#define NETLINK_FIREWALL_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_FIREWALL_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_FIREWALL_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_FIREWALL_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_FIREWALL_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_TCPDIAG_SOCKET__IOCTL 0x00000001UL +#define NETLINK_TCPDIAG_SOCKET__READ 0x00000002UL +#define NETLINK_TCPDIAG_SOCKET__WRITE 0x00000004UL +#define NETLINK_TCPDIAG_SOCKET__CREATE 0x00000008UL +#define NETLINK_TCPDIAG_SOCKET__GETATTR 0x00000010UL +#define NETLINK_TCPDIAG_SOCKET__SETATTR 0x00000020UL +#define NETLINK_TCPDIAG_SOCKET__LOCK 0x00000040UL +#define NETLINK_TCPDIAG_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_TCPDIAG_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_TCPDIAG_SOCKET__APPEND 0x00000200UL +#define NETLINK_TCPDIAG_SOCKET__BIND 0x00000400UL +#define NETLINK_TCPDIAG_SOCKET__CONNECT 0x00000800UL +#define NETLINK_TCPDIAG_SOCKET__LISTEN 0x00001000UL +#define NETLINK_TCPDIAG_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_TCPDIAG_SOCKET__GETOPT 0x00004000UL +#define NETLINK_TCPDIAG_SOCKET__SETOPT 0x00008000UL +#define NETLINK_TCPDIAG_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_TCPDIAG_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_TCPDIAG_SOCKET__SENDTO 0x00040000UL +#define NETLINK_TCPDIAG_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_TCPDIAG_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_TCPDIAG_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_TCPDIAG_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_NFLOG_SOCKET__IOCTL 0x00000001UL +#define NETLINK_NFLOG_SOCKET__READ 0x00000002UL +#define NETLINK_NFLOG_SOCKET__WRITE 0x00000004UL +#define NETLINK_NFLOG_SOCKET__CREATE 0x00000008UL +#define NETLINK_NFLOG_SOCKET__GETATTR 0x00000010UL +#define NETLINK_NFLOG_SOCKET__SETATTR 0x00000020UL +#define NETLINK_NFLOG_SOCKET__LOCK 0x00000040UL +#define NETLINK_NFLOG_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_NFLOG_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_NFLOG_SOCKET__APPEND 0x00000200UL +#define NETLINK_NFLOG_SOCKET__BIND 0x00000400UL +#define NETLINK_NFLOG_SOCKET__CONNECT 0x00000800UL +#define NETLINK_NFLOG_SOCKET__LISTEN 0x00001000UL +#define NETLINK_NFLOG_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_NFLOG_SOCKET__GETOPT 0x00004000UL +#define NETLINK_NFLOG_SOCKET__SETOPT 0x00008000UL +#define NETLINK_NFLOG_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_NFLOG_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_NFLOG_SOCKET__SENDTO 0x00040000UL +#define NETLINK_NFLOG_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_NFLOG_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_NFLOG_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_XFRM_SOCKET__IOCTL 0x00000001UL +#define NETLINK_XFRM_SOCKET__READ 0x00000002UL +#define NETLINK_XFRM_SOCKET__WRITE 0x00000004UL +#define NETLINK_XFRM_SOCKET__CREATE 0x00000008UL +#define NETLINK_XFRM_SOCKET__GETATTR 0x00000010UL +#define NETLINK_XFRM_SOCKET__SETATTR 0x00000020UL +#define NETLINK_XFRM_SOCKET__LOCK 0x00000040UL +#define NETLINK_XFRM_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_XFRM_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_XFRM_SOCKET__APPEND 0x00000200UL +#define NETLINK_XFRM_SOCKET__BIND 0x00000400UL +#define NETLINK_XFRM_SOCKET__CONNECT 0x00000800UL +#define NETLINK_XFRM_SOCKET__LISTEN 0x00001000UL +#define NETLINK_XFRM_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_XFRM_SOCKET__GETOPT 0x00004000UL +#define NETLINK_XFRM_SOCKET__SETOPT 0x00008000UL +#define NETLINK_XFRM_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_XFRM_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_XFRM_SOCKET__SENDTO 0x00040000UL +#define NETLINK_XFRM_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_XFRM_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_XFRM_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_XFRM_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_XFRM_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_SELINUX_SOCKET__IOCTL 0x00000001UL +#define NETLINK_SELINUX_SOCKET__READ 0x00000002UL +#define NETLINK_SELINUX_SOCKET__WRITE 0x00000004UL +#define NETLINK_SELINUX_SOCKET__CREATE 0x00000008UL +#define NETLINK_SELINUX_SOCKET__GETATTR 0x00000010UL +#define NETLINK_SELINUX_SOCKET__SETATTR 0x00000020UL +#define NETLINK_SELINUX_SOCKET__LOCK 0x00000040UL +#define NETLINK_SELINUX_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_SELINUX_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_SELINUX_SOCKET__APPEND 0x00000200UL +#define NETLINK_SELINUX_SOCKET__BIND 0x00000400UL +#define NETLINK_SELINUX_SOCKET__CONNECT 0x00000800UL +#define NETLINK_SELINUX_SOCKET__LISTEN 0x00001000UL +#define NETLINK_SELINUX_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_SELINUX_SOCKET__GETOPT 0x00004000UL +#define NETLINK_SELINUX_SOCKET__SETOPT 0x00008000UL +#define NETLINK_SELINUX_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_SELINUX_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_SELINUX_SOCKET__SENDTO 0x00040000UL +#define NETLINK_SELINUX_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_SELINUX_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_SELINUX_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_AUDIT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_AUDIT_SOCKET__READ 0x00000002UL +#define NETLINK_AUDIT_SOCKET__WRITE 0x00000004UL +#define NETLINK_AUDIT_SOCKET__CREATE 0x00000008UL +#define NETLINK_AUDIT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_AUDIT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_AUDIT_SOCKET__LOCK 0x00000040UL +#define NETLINK_AUDIT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_AUDIT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_AUDIT_SOCKET__APPEND 0x00000200UL +#define NETLINK_AUDIT_SOCKET__BIND 0x00000400UL +#define NETLINK_AUDIT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_AUDIT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_AUDIT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_AUDIT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_AUDIT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_AUDIT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_AUDIT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_AUDIT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_AUDIT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_AUDIT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_AUDIT_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY 0x01000000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV 0x02000000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT 0x04000000UL +#define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL +#define NETLINK_IP6FW_SOCKET__READ 0x00000002UL +#define NETLINK_IP6FW_SOCKET__WRITE 0x00000004UL +#define NETLINK_IP6FW_SOCKET__CREATE 0x00000008UL +#define NETLINK_IP6FW_SOCKET__GETATTR 0x00000010UL +#define NETLINK_IP6FW_SOCKET__SETATTR 0x00000020UL +#define NETLINK_IP6FW_SOCKET__LOCK 0x00000040UL +#define NETLINK_IP6FW_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_IP6FW_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_IP6FW_SOCKET__APPEND 0x00000200UL +#define NETLINK_IP6FW_SOCKET__BIND 0x00000400UL +#define NETLINK_IP6FW_SOCKET__CONNECT 0x00000800UL +#define NETLINK_IP6FW_SOCKET__LISTEN 0x00001000UL +#define NETLINK_IP6FW_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_IP6FW_SOCKET__GETOPT 0x00004000UL +#define NETLINK_IP6FW_SOCKET__SETOPT 0x00008000UL +#define NETLINK_IP6FW_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_IP6FW_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_IP6FW_SOCKET__SENDTO 0x00040000UL +#define NETLINK_IP6FW_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_IP6FW_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_IP6FW_SOCKET__NAME_BIND 0x00200000UL +#define NETLINK_IP6FW_SOCKET__NLMSG_READ 0x00400000UL +#define NETLINK_IP6FW_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_DNRT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_DNRT_SOCKET__READ 0x00000002UL +#define NETLINK_DNRT_SOCKET__WRITE 0x00000004UL +#define NETLINK_DNRT_SOCKET__CREATE 0x00000008UL +#define NETLINK_DNRT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_DNRT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_DNRT_SOCKET__LOCK 0x00000040UL +#define NETLINK_DNRT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_DNRT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_DNRT_SOCKET__APPEND 0x00000200UL +#define NETLINK_DNRT_SOCKET__BIND 0x00000400UL +#define NETLINK_DNRT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_DNRT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_DNRT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_DNRT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_DNRT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_DNRT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_DNRT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_DNRT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_DNRT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_DNRT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_DNRT_SOCKET__NAME_BIND 0x00200000UL +#define DBUS__ACQUIRE_SVC 0x00000001UL +#define DBUS__SEND_MSG 0x00000002UL +#define NSCD__GETPWD 0x00000001UL +#define NSCD__GETGRP 0x00000002UL +#define NSCD__GETHOST 0x00000004UL +#define NSCD__GETSTAT 0x00000008UL +#define NSCD__ADMIN 0x00000010UL +#define NSCD__SHMEMPWD 0x00000020UL +#define NSCD__SHMEMGRP 0x00000040UL +#define NSCD__SHMEMHOST 0x00000080UL +#define NSCD__GETSERV 0x00000100UL +#define NSCD__SHMEMSERV 0x00000200UL +#define NSCD__GETNETGRP 0x00000400UL +#define NSCD__SHMEMNETGRP 0x00000800UL +#define ASSOCIATION__SENDTO 0x00000001UL +#define ASSOCIATION__RECVFROM 0x00000002UL +#define ASSOCIATION__SETCONTEXT 0x00000004UL +#define ASSOCIATION__POLMATCH 0x00000008UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__WRITE 0x00000004UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__CREATE 0x00000008UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__GETATTR 0x00000010UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SETATTR 0x00000020UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__LOCK 0x00000040UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELFROM 0x00000080UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELTO 0x00000100UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__APPEND 0x00000200UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__BIND 0x00000400UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__CONNECT 0x00000800UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__LISTEN 0x00001000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__ACCEPT 0x00002000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__GETOPT 0x00004000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SETOPT 0x00008000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SHUTDOWN 0x00010000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RECVFROM 0x00020000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SENDTO 0x00040000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__RECV_MSG 0x00080000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG 0x00100000UL +#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND 0x00200000UL +#define APPLETALK_SOCKET__IOCTL 0x00000001UL +#define APPLETALK_SOCKET__READ 0x00000002UL +#define APPLETALK_SOCKET__WRITE 0x00000004UL +#define APPLETALK_SOCKET__CREATE 0x00000008UL +#define APPLETALK_SOCKET__GETATTR 0x00000010UL +#define APPLETALK_SOCKET__SETATTR 0x00000020UL +#define APPLETALK_SOCKET__LOCK 0x00000040UL +#define APPLETALK_SOCKET__RELABELFROM 0x00000080UL +#define APPLETALK_SOCKET__RELABELTO 0x00000100UL +#define APPLETALK_SOCKET__APPEND 0x00000200UL +#define APPLETALK_SOCKET__BIND 0x00000400UL +#define APPLETALK_SOCKET__CONNECT 0x00000800UL +#define APPLETALK_SOCKET__LISTEN 0x00001000UL +#define APPLETALK_SOCKET__ACCEPT 0x00002000UL +#define APPLETALK_SOCKET__GETOPT 0x00004000UL +#define APPLETALK_SOCKET__SETOPT 0x00008000UL +#define APPLETALK_SOCKET__SHUTDOWN 0x00010000UL +#define APPLETALK_SOCKET__RECVFROM 0x00020000UL +#define APPLETALK_SOCKET__SENDTO 0x00040000UL +#define APPLETALK_SOCKET__RECV_MSG 0x00080000UL +#define APPLETALK_SOCKET__SEND_MSG 0x00100000UL +#define APPLETALK_SOCKET__NAME_BIND 0x00200000UL +#define PACKET__SEND 0x00000001UL +#define PACKET__RECV 0x00000002UL +#define PACKET__RELABELTO 0x00000004UL +#define PACKET__FLOW_IN 0x00000008UL +#define PACKET__FLOW_OUT 0x00000010UL +#define PACKET__FORWARD_IN 0x00000020UL +#define PACKET__FORWARD_OUT 0x00000040UL +#define KEY__VIEW 0x00000001UL +#define KEY__READ 0x00000002UL +#define KEY__WRITE 0x00000004UL +#define KEY__SEARCH 0x00000008UL +#define KEY__LINK 0x00000010UL +#define KEY__SETATTR 0x00000020UL +#define KEY__CREATE 0x00000040UL +#define CONTEXT__TRANSLATE 0x00000001UL +#define CONTEXT__CONTAINS 0x00000002UL +#define DCCP_SOCKET__IOCTL 0x00000001UL +#define DCCP_SOCKET__READ 0x00000002UL +#define DCCP_SOCKET__WRITE 0x00000004UL +#define DCCP_SOCKET__CREATE 0x00000008UL +#define DCCP_SOCKET__GETATTR 0x00000010UL +#define DCCP_SOCKET__SETATTR 0x00000020UL +#define DCCP_SOCKET__LOCK 0x00000040UL +#define DCCP_SOCKET__RELABELFROM 0x00000080UL +#define DCCP_SOCKET__RELABELTO 0x00000100UL +#define DCCP_SOCKET__APPEND 0x00000200UL +#define DCCP_SOCKET__BIND 0x00000400UL +#define DCCP_SOCKET__CONNECT 0x00000800UL +#define DCCP_SOCKET__LISTEN 0x00001000UL +#define DCCP_SOCKET__ACCEPT 0x00002000UL +#define DCCP_SOCKET__GETOPT 0x00004000UL +#define DCCP_SOCKET__SETOPT 0x00008000UL +#define DCCP_SOCKET__SHUTDOWN 0x00010000UL +#define DCCP_SOCKET__RECVFROM 0x00020000UL +#define DCCP_SOCKET__SENDTO 0x00040000UL +#define DCCP_SOCKET__RECV_MSG 0x00080000UL +#define DCCP_SOCKET__SEND_MSG 0x00100000UL +#define DCCP_SOCKET__NAME_BIND 0x00200000UL +#define DCCP_SOCKET__NODE_BIND 0x00400000UL +#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL +#define MEMPROTECT__MMAP_ZERO 0x00000001UL +#define DB_DATABASE__CREATE 0x00000001UL +#define DB_DATABASE__DROP 0x00000002UL +#define DB_DATABASE__GETATTR 0x00000004UL +#define DB_DATABASE__SETATTR 0x00000008UL +#define DB_DATABASE__RELABELFROM 0x00000010UL +#define DB_DATABASE__RELABELTO 0x00000020UL +#define DB_DATABASE__ACCESS 0x00000040UL +#define DB_DATABASE__INSTALL_MODULE 0x00000080UL +#define DB_DATABASE__LOAD_MODULE 0x00000100UL +#define DB_DATABASE__GET_PARAM 0x00000200UL +#define DB_DATABASE__SET_PARAM 0x00000400UL +#define DB_TABLE__CREATE 0x00000001UL +#define DB_TABLE__DROP 0x00000002UL +#define DB_TABLE__GETATTR 0x00000004UL +#define DB_TABLE__SETATTR 0x00000008UL +#define DB_TABLE__RELABELFROM 0x00000010UL +#define DB_TABLE__RELABELTO 0x00000020UL +#define DB_TABLE__USE 0x00000040UL +#define DB_TABLE__SELECT 0x00000080UL +#define DB_TABLE__UPDATE 0x00000100UL +#define DB_TABLE__INSERT 0x00000200UL +#define DB_TABLE__DELETE 0x00000400UL +#define DB_TABLE__LOCK 0x00000800UL +#define DB_PROCEDURE__CREATE 0x00000001UL +#define DB_PROCEDURE__DROP 0x00000002UL +#define DB_PROCEDURE__GETATTR 0x00000004UL +#define DB_PROCEDURE__SETATTR 0x00000008UL +#define DB_PROCEDURE__RELABELFROM 0x00000010UL +#define DB_PROCEDURE__RELABELTO 0x00000020UL +#define DB_PROCEDURE__EXECUTE 0x00000040UL +#define DB_PROCEDURE__ENTRYPOINT 0x00000080UL +#define DB_COLUMN__CREATE 0x00000001UL +#define DB_COLUMN__DROP 0x00000002UL +#define DB_COLUMN__GETATTR 0x00000004UL +#define DB_COLUMN__SETATTR 0x00000008UL +#define DB_COLUMN__RELABELFROM 0x00000010UL +#define DB_COLUMN__RELABELTO 0x00000020UL +#define DB_COLUMN__USE 0x00000040UL +#define DB_COLUMN__SELECT 0x00000080UL +#define DB_COLUMN__UPDATE 0x00000100UL +#define DB_COLUMN__INSERT 0x00000200UL +#define DB_TUPLE__RELABELFROM 0x00000001UL +#define DB_TUPLE__RELABELTO 0x00000002UL +#define DB_TUPLE__USE 0x00000004UL +#define DB_TUPLE__SELECT 0x00000008UL +#define DB_TUPLE__UPDATE 0x00000010UL +#define DB_TUPLE__INSERT 0x00000020UL +#define DB_TUPLE__DELETE 0x00000040UL +#define DB_BLOB__CREATE 0x00000001UL +#define DB_BLOB__DROP 0x00000002UL +#define DB_BLOB__GETATTR 0x00000004UL +#define DB_BLOB__SETATTR 0x00000008UL +#define DB_BLOB__RELABELFROM 0x00000010UL +#define DB_BLOB__RELABELTO 0x00000020UL +#define DB_BLOB__READ 0x00000040UL +#define DB_BLOB__WRITE 0x00000080UL +#define DB_BLOB__IMPORT 0x00000100UL +#define DB_BLOB__EXPORT 0x00000200UL +#define PEER__RECV 0x00000001UL +#define X_APPLICATION_DATA__PASTE 0x00000001UL +#define X_APPLICATION_DATA__PASTE_AFTER_CONFIRM 0x00000002UL +#define X_APPLICATION_DATA__COPY 0x00000004UL diff --git a/include/selinux/avc.h b/include/selinux/avc.h new file mode 100644 index 0000000..b4bc6f3 --- /dev/null +++ b/include/selinux/avc.h @@ -0,0 +1,511 @@ +/* + * Access vector cache interface for object managers. + * + * Author : Eamon Walsh + */ +#ifndef _SELINUX_AVC_H_ +#define _SELINUX_AVC_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SID format and operations + */ +struct security_id { + char * ctx; + unsigned int refcnt; +}; +typedef struct security_id *security_id_t; + +#define SECSID_WILD (security_id_t)NULL /* unspecified SID */ + +/** + * avc_sid_to_context - get copy of context corresponding to SID. + * @sid: input SID + * @ctx: pointer to context reference + * + * Return a copy of the security context corresponding to the input + * @sid in the memory referenced by @ctx. The caller is expected to + * free the context with freecon(). Return %0 on success, -%1 on + * failure, with @errno set to %ENOMEM if insufficient memory was + * available to make the copy, or %EINVAL if the input SID is invalid. + */ +int avc_sid_to_context(security_id_t sid, char ** ctx); +int avc_sid_to_context_raw(security_id_t sid, char ** ctx); + +/** + * avc_context_to_sid - get SID for context. + * @ctx: input security context + * @sid: pointer to SID reference + * + * Look up security context @ctx in SID table, making + * a new entry if @ctx is not found. Increment the + * reference counter for the SID. Store a pointer + * to the SID structure into the memory referenced by @sid, + * returning %0 on success or -%1 on error with @errno set. + */ +int avc_context_to_sid(const char * ctx, security_id_t * sid); +int avc_context_to_sid_raw(const char * ctx, security_id_t * sid); + +/** + * sidget - increment SID reference counter. + * @sid: SID reference + * + * Increment the reference counter for @sid, indicating that + * @sid is in use by an (additional) object. Return the + * new reference count, or zero if @sid is invalid (has zero + * reference count). Note that avc_context_to_sid() also + * increments reference counts. + */ +int sidget(security_id_t sid); + +/** + * sidput - decrement SID reference counter. + * @sid: SID reference + * + * Decrement the reference counter for @sid, indicating that + * a reference to @sid is no longer in use. Return the + * new reference count. When the reference count reaches + * zero, the SID is invalid, and avc_context_to_sid() must + * be called to obtain a new SID for the security context. + */ +int sidput(security_id_t sid); + +/** + * avc_get_initial_sid - get SID for an initial kernel security identifier + * @name: input name of initial kernel security identifier + * @sid: pointer to a SID reference + * + * Get the context for an initial kernel security identifier specified by + * @name using security_get_initial_context() and then call + * avc_context_to_sid() to get the corresponding SID. + */ +int avc_get_initial_sid(const char *name, security_id_t * sid); + +/* + * AVC entry + */ +struct avc_entry; +struct avc_entry_ref { + struct avc_entry *ae; +}; + +/** + * avc_entry_ref_init - initialize an AVC entry reference. + * @aeref: pointer to avc entry reference structure + * + * Use this macro to initialize an avc entry reference structure + * before first use. These structures are passed to avc_has_perm(), + * which stores cache entry references in them. They can increase + * performance on repeated queries. + */ +#define avc_entry_ref_init(aeref) ((aeref)->ae = NULL) + +/* + * User-provided callbacks for memory, auditing, and locking + */ + +/* These structures are passed by reference to avc_init(). Passing + * a NULL reference will cause the AVC to use a default. The default + * memory callbacks are malloc() and free(). The default logging method + * is to print on stderr. If no thread callbacks are passed, a separate + * listening thread won't be started for kernel policy change messages. + * If no locking callbacks are passed, no locking will take place. + */ +struct avc_memory_callback { + /* malloc() equivalent. */ + void *(*func_malloc) (size_t size); + /* free() equivalent. */ + void (*func_free) (void *ptr); + /* Note that these functions should set errno on failure. + If not, some avc routines may return -1 without errno set. */ +}; + +struct avc_log_callback { + /* log the printf-style format and arguments. */ + void +#ifdef __GNUC__ +__attribute__ ((format(printf, 1, 2))) +#endif + (*func_log) (const char *fmt, ...); + /* store a string representation of auditdata (corresponding + to the given security class) into msgbuf. */ + void (*func_audit) (void *auditdata, security_class_t cls, + char *msgbuf, size_t msgbufsize); +}; + +struct avc_thread_callback { + /* create and start a thread, returning an opaque pointer to it; + the thread should run the given function. */ + void *(*func_create_thread) (void (*run) (void)); + /* cancel a given thread and free its resources. */ + void (*func_stop_thread) (void *thread); +}; + +struct avc_lock_callback { + /* create a lock and return an opaque pointer to it. */ + void *(*func_alloc_lock) (void); + /* obtain a given lock, blocking if necessary. */ + void (*func_get_lock) (void *lock); + /* release a given lock. */ + void (*func_release_lock) (void *lock); + /* destroy a given lock (free memory, etc.) */ + void (*func_free_lock) (void *lock); +}; + +/* + * Available options + */ + +/* no-op option, useful for unused slots in an array of options */ +#define AVC_OPT_UNUSED 0 +/* override kernel enforcing mode (boolean value) */ +#define AVC_OPT_SETENFORCE 1 + +/* + * AVC operations + */ + +/** + * avc_init - Initialize the AVC. + * @msgprefix: prefix for log messages + * @mem_callbacks: user-supplied memory callbacks + * @log_callbacks: user-supplied logging callbacks + * @thread_callbacks: user-supplied threading callbacks + * @lock_callbacks: user-supplied locking callbacks + * + * Initialize the access vector cache. Return %0 on + * success or -%1 with @errno set on failure. + * If @msgprefix is NULL, use "uavc". If any callback + * structure references are NULL, use default methods + * for those callbacks (see the definition of the callback + * structures above). + */ +int avc_init(const char *msgprefix, + const struct avc_memory_callback *mem_callbacks, + const struct avc_log_callback *log_callbacks, + const struct avc_thread_callback *thread_callbacks, + const struct avc_lock_callback *lock_callbacks); + +/** + * avc_open - Initialize the AVC. + * @opts: array of selabel_opt structures specifying AVC options or NULL. + * @nopts: number of elements in opts array or zero for no options. + * + * This function is identical to avc_init(), except the message prefix + * is set to "avc" and any callbacks desired should be specified via + * selinux_set_callback(). Available options are listed above. + */ +int avc_open(struct selinux_opt *opts, unsigned nopts); + +/** + * avc_cleanup - Remove unused SIDs and AVC entries. + * + * Search the SID table for SID structures with zero + * reference counts, and remove them along with all + * AVC entries that reference them. This can be used + * to return memory to the system. + */ +void avc_cleanup(void); + +/** + * avc_reset - Flush the cache and reset statistics. + * + * Remove all entries from the cache and reset all access + * statistics (as returned by avc_cache_stats()) to zero. + * The SID mapping is not affected. Return %0 on success, + * -%1 with @errno set on error. + */ +int avc_reset(void); + +/** + * avc_destroy - Free all AVC structures. + * + * Destroy all AVC structures and free all allocated + * memory. User-supplied locking, memory, and audit + * callbacks will be retained, but security-event + * callbacks will not. All SID's will be invalidated. + * User must call avc_init() if further use of AVC is desired. + */ +void avc_destroy(void); + +/** + * avc_has_perm_noaudit - Check permissions but perform no auditing. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @avd: access vector decisions + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions, and return a copy of the decisions + * in @avd. Return %0 if all @requested permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied, or to another value + * upon other errors. This function is typically called by avc_has_perm(), + * but may also be called directly to separate permission checking from + * auditing, e.g. in cases where a lock must be held for the check but + * should be released for the auditing. + */ +int avc_has_perm_noaudit(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, struct av_decision *avd); + +/** + * avc_has_perm - Check permissions and perform any appropriate auditing. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @auditdata: auxiliary audit data + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions. Audit the granting or denial of + * permissions in accordance with the policy. Return %0 if all @requested + * permissions are granted, -%1 with @errno set to %EACCES if any permissions + * are denied or to another value upon other errors. + */ +int avc_has_perm(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata); + +/** + * avc_audit - Audit the granting or denial of permissions. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions + * @avd: access vector decisions + * @result: result from avc_has_perm_noaudit + * @auditdata: auxiliary audit data + * + * Audit the granting or denial of permissions in accordance + * with the policy. This function is typically called by + * avc_has_perm() after a permission check, but can also be + * called directly by callers who use avc_has_perm_noaudit() + * in order to separate the permission check from the auditing. + * For example, this separation is useful when the permission check must + * be performed under a lock, to allow the lock to be released + * before calling the auditing code. + */ +void avc_audit(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct av_decision *avd, int result, void *auditdata); + +/** + * avc_compute_create - Compute SID for labeling a new object. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @newsid: pointer to SID reference + * + * Call the security server to obtain a context for labeling a + * new object. Look up the context in the SID table, making + * a new entry if not found. Increment the reference counter + * for the SID. Store a pointer to the SID structure into the + * memory referenced by @newsid, returning %0 on success or -%1 on + * error with @errno set. + */ +int avc_compute_create(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, security_id_t * newsid); + +/** + * avc_compute_member - Compute SID for polyinstantation. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @newsid: pointer to SID reference + * + * Call the security server to obtain a context for labeling an + * object instance. Look up the context in the SID table, making + * a new entry if not found. Increment the reference counter + * for the SID. Store a pointer to the SID structure into the + * memory referenced by @newsid, returning %0 on success or -%1 on + * error with @errno set. + */ +int avc_compute_member(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, security_id_t * newsid); + +/* + * security event callback facility + */ + +/* security events */ +#define AVC_CALLBACK_GRANT 1 +#define AVC_CALLBACK_TRY_REVOKE 2 +#define AVC_CALLBACK_REVOKE 4 +#define AVC_CALLBACK_RESET 8 +#define AVC_CALLBACK_AUDITALLOW_ENABLE 16 +#define AVC_CALLBACK_AUDITALLOW_DISABLE 32 +#define AVC_CALLBACK_AUDITDENY_ENABLE 64 +#define AVC_CALLBACK_AUDITDENY_DISABLE 128 + +/** + * avc_add_callback - Register a callback for security events. + * @callback: callback function + * @events: bitwise OR of desired security events + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions + * + * Register a callback function for events in the set @events + * related to the SID pair (@ssid, @tsid) and + * and the permissions @perms, interpreting + * @perms based on @tclass. Returns %0 on success or + * -%1 if insufficient memory exists to add the callback. + */ +int avc_add_callback(int (*callback) + (uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms, + access_vector_t * out_retained), + uint32_t events, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms); + +/* + * AVC statistics + */ + +/* If set, cache statistics are tracked. This may + * become a compile-time option in the future. + */ +#define AVC_CACHE_STATS 1 + +struct avc_cache_stats { + unsigned entry_lookups; + unsigned entry_hits; + unsigned entry_misses; + unsigned entry_discards; + unsigned cav_lookups; + unsigned cav_hits; + unsigned cav_probes; + unsigned cav_misses; +}; + +/** + * avc_cache_stats - get cache access statistics. + * @stats: reference to statistics structure + * + * Fill the supplied structure with information about AVC + * activity since the last call to avc_init() or + * avc_reset(). See the structure definition for + * details. + */ +void avc_cache_stats(struct avc_cache_stats *stats); + +/** + * avc_av_stats - log av table statistics. + * + * Log a message with information about the size and + * distribution of the access vector table. The audit + * callback is used to print the message. + */ +void avc_av_stats(void); + +/** + * avc_sid_stats - log SID table statistics. + * + * Log a message with information about the size and + * distribution of the SID table. The audit callback + * is used to print the message. + */ +void avc_sid_stats(void); + +/** + * avc_netlink_open - Create a netlink socket and connect to the kernel. + */ +int avc_netlink_open(int blocking); + +/** + * avc_netlink_loop - Wait for netlink messages from the kernel + */ +void avc_netlink_loop(void); + +/** + * avc_netlink_close - Close the netlink socket + */ +void avc_netlink_close(void); + +/** + * avc_netlink_acquire_fd - Acquire netlink socket fd. + * + * Allows the application to manage messages from the netlink socket in + * its own main loop. + */ +int avc_netlink_acquire_fd(void); + +/** + * avc_netlink_release_fd - Release netlink socket fd. + * + * Returns ownership of the netlink socket to the library. + */ +void avc_netlink_release_fd(void); + +/** + * avc_netlink_check_nb - Check netlink socket for new messages. + * + * Called by the application when using avc_netlink_acquire_fd() to + * process kernel netlink events. + */ +int avc_netlink_check_nb(void); + +/** + * selinux_status_open - Open and map SELinux kernel status page + * + */ +int selinux_status_open(int fallback); + +/** + * selinux_status_close - Unmap and close SELinux kernel status page + * + */ +void selinux_status_close(void); + +/** + * selinux_status_updated - Inform us whether the kernel status has been updated + * + */ +int selinux_status_updated(void); + +/** + * selinux_status_getenforce - Get the enforce flag value + * + */ +int selinux_status_getenforce(void); + +/** + * selinux_status_policyload - Get the number of policy reloaded + * + */ +int selinux_status_policyload(void); + +/** + * selinux_status_deny_unknown - Get the behavior for undefined classes/permissions + * + */ +int selinux_status_deny_unknown(void); + +#ifdef __cplusplus +} +#endif +#endif /* _SELINUX_AVC_H_ */ diff --git a/include/selinux/context.h b/include/selinux/context.h new file mode 100644 index 0000000..949fb1e --- /dev/null +++ b/include/selinux/context.h @@ -0,0 +1,50 @@ +#ifndef _SELINUX_CONTEXT_H_ +#define _SELINUX_CONTEXT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Functions to deal with security contexts in user space. + */ + + typedef struct { + void *ptr; + } context_s_t; + + typedef context_s_t *context_t; + +/* Return a new context initialized to a context string */ + + extern context_t context_new(const char *); + +/* + * Return a pointer to the string value of the context_t + * Valid until the next call to context_str or context_free + * for the same context_t* + */ + + extern char *context_str(context_t); + +/* Free the storage used by a context */ + extern void context_free(context_t); + +/* Get a pointer to the string value of a context component */ + + extern const char *context_type_get(context_t); + extern const char *context_range_get(context_t); + extern const char *context_role_get(context_t); + extern const char *context_user_get(context_t); + +/* Set a context component. Returns nonzero if unsuccessful */ + + extern int context_type_set(context_t, const char *); + extern int context_range_set(context_t, const char *); + extern int context_role_set(context_t, const char *); + extern int context_user_set(context_t, const char *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/selinux/flask.h b/include/selinux/flask.h new file mode 100644 index 0000000..8128223 --- /dev/null +++ b/include/selinux/flask.h @@ -0,0 +1,118 @@ +/* This file is automatically generated. Do not edit. */ +#ifndef _SELINUX_FLASK_H_ +#define _SELINUX_FLASK_H_ + +#warning "Please remove any #include's of this header in your source code." +#warning "Instead, use string_to_security_class() to map the class name to a value." + +/* + * Security object class definitions + */ +#define SECCLASS_SECURITY 1 +#define SECCLASS_PROCESS 2 +#define SECCLASS_SYSTEM 3 +#define SECCLASS_CAPABILITY 4 +#define SECCLASS_FILESYSTEM 5 +#define SECCLASS_FILE 6 +#define SECCLASS_DIR 7 +#define SECCLASS_FD 8 +#define SECCLASS_LNK_FILE 9 +#define SECCLASS_CHR_FILE 10 +#define SECCLASS_BLK_FILE 11 +#define SECCLASS_SOCK_FILE 12 +#define SECCLASS_FIFO_FILE 13 +#define SECCLASS_SOCKET 14 +#define SECCLASS_TCP_SOCKET 15 +#define SECCLASS_UDP_SOCKET 16 +#define SECCLASS_RAWIP_SOCKET 17 +#define SECCLASS_NODE 18 +#define SECCLASS_NETIF 19 +#define SECCLASS_NETLINK_SOCKET 20 +#define SECCLASS_PACKET_SOCKET 21 +#define SECCLASS_KEY_SOCKET 22 +#define SECCLASS_UNIX_STREAM_SOCKET 23 +#define SECCLASS_UNIX_DGRAM_SOCKET 24 +#define SECCLASS_SEM 25 +#define SECCLASS_MSG 26 +#define SECCLASS_MSGQ 27 +#define SECCLASS_SHM 28 +#define SECCLASS_IPC 29 +#define SECCLASS_PASSWD 30 +#define SECCLASS_X_DRAWABLE 31 +#define SECCLASS_X_SCREEN 32 +#define SECCLASS_X_GC 33 +#define SECCLASS_X_FONT 34 +#define SECCLASS_X_COLORMAP 35 +#define SECCLASS_X_PROPERTY 36 +#define SECCLASS_X_SELECTION 37 +#define SECCLASS_X_CURSOR 38 +#define SECCLASS_X_CLIENT 39 +#define SECCLASS_X_DEVICE 40 +#define SECCLASS_X_SERVER 41 +#define SECCLASS_X_EXTENSION 42 +#define SECCLASS_NETLINK_ROUTE_SOCKET 43 +#define SECCLASS_NETLINK_FIREWALL_SOCKET 44 +#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45 +#define SECCLASS_NETLINK_NFLOG_SOCKET 46 +#define SECCLASS_NETLINK_XFRM_SOCKET 47 +#define SECCLASS_NETLINK_SELINUX_SOCKET 48 +#define SECCLASS_NETLINK_AUDIT_SOCKET 49 +#define SECCLASS_NETLINK_IP6FW_SOCKET 50 +#define SECCLASS_NETLINK_DNRT_SOCKET 51 +#define SECCLASS_DBUS 52 +#define SECCLASS_NSCD 53 +#define SECCLASS_ASSOCIATION 54 +#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 +#define SECCLASS_APPLETALK_SOCKET 56 +#define SECCLASS_PACKET 57 +#define SECCLASS_KEY 58 +#define SECCLASS_CONTEXT 59 +#define SECCLASS_DCCP_SOCKET 60 +#define SECCLASS_MEMPROTECT 61 +#define SECCLASS_DB_DATABASE 62 +#define SECCLASS_DB_TABLE 63 +#define SECCLASS_DB_PROCEDURE 64 +#define SECCLASS_DB_COLUMN 65 +#define SECCLASS_DB_TUPLE 66 +#define SECCLASS_DB_BLOB 67 +#define SECCLASS_PEER 68 +#define SECCLASS_CAPABILITY2 69 +#define SECCLASS_X_RESOURCE 70 +#define SECCLASS_X_EVENT 71 +#define SECCLASS_X_SYNTHETIC_EVENT 72 +#define SECCLASS_X_APPLICATION_DATA 73 + +/* + * Security identifier indices for initial entities + */ +#define SECINITSID_KERNEL 1 +#define SECINITSID_SECURITY 2 +#define SECINITSID_UNLABELED 3 +#define SECINITSID_FS 4 +#define SECINITSID_FILE 5 +#define SECINITSID_FILE_LABELS 6 +#define SECINITSID_INIT 7 +#define SECINITSID_ANY_SOCKET 8 +#define SECINITSID_PORT 9 +#define SECINITSID_NETIF 10 +#define SECINITSID_NETMSG 11 +#define SECINITSID_NODE 12 +#define SECINITSID_IGMP_PACKET 13 +#define SECINITSID_ICMP_SOCKET 14 +#define SECINITSID_TCP_SOCKET 15 +#define SECINITSID_SYSCTL_MODPROBE 16 +#define SECINITSID_SYSCTL 17 +#define SECINITSID_SYSCTL_FS 18 +#define SECINITSID_SYSCTL_KERNEL 19 +#define SECINITSID_SYSCTL_NET 20 +#define SECINITSID_SYSCTL_NET_UNIX 21 +#define SECINITSID_SYSCTL_VM 22 +#define SECINITSID_SYSCTL_DEV 23 +#define SECINITSID_KMOD 24 +#define SECINITSID_POLICY 25 +#define SECINITSID_SCMP_PACKET 26 +#define SECINITSID_DEVNULL 27 + +#define SECINITSID_NUM 27 + +#endif diff --git a/include/selinux/get_context_list.h b/include/selinux/get_context_list.h new file mode 100644 index 0000000..a15b9c4 --- /dev/null +++ b/include/selinux/get_context_list.h @@ -0,0 +1,82 @@ +#ifndef _SELINUX_GET_SID_LIST_H_ +#define _SELINUX_GET_SID_LIST_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SELINUX_DEFAULTUSER "user_u" + +/* Get an ordered list of authorized security contexts for a user session + for 'user' spawned by 'fromcon' and set *conary to refer to the + NULL-terminated array of contexts. Every entry in the list will + be authorized by the policy, but the ordering is subject to user + customizable preferences. Returns number of entries in *conary. + If 'fromcon' is NULL, defaults to current context. + Caller must free via freeconary. */ + extern int get_ordered_context_list(const char *user, + char * fromcon, + char *** list); + +/* As above, but use the provided MLS level rather than the + default level for the user. */ + int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, + char *** list); + +/* Get the default security context for a user session for 'user' + spawned by 'fromcon' and set *newcon to refer to it. The context + will be one of those authorized by the policy, but the selection + of a default is subject to user customizable preferences. + If 'fromcon' is NULL, defaults to current context. + Returns 0 on success or -1 otherwise. + Caller must free via freecon. */ + extern int get_default_context(const char *user, + char * fromcon, + char ** newcon); + +/* As above, but use the provided MLS level rather than the + default level for the user. */ + int get_default_context_with_level(const char *user, + const char *level, + char * fromcon, + char ** newcon); + +/* Same as get_default_context, but only return a context + that has the specified role. If no reachable context exists + for the user with that role, then return -1. */ + int get_default_context_with_role(const char *user, + const char *role, + char * fromcon, + char ** newcon); + +/* Same as get_default_context, but only return a context + that has the specified role and level. If no reachable context exists + for the user with that role, then return -1. */ + int get_default_context_with_rolelevel(const char *user, + const char *role, + const char *level, + char * fromcon, + char ** newcon); + +/* Given a list of authorized security contexts for the user, + query the user to select one and set *newcon to refer to it. + Caller must free via freecon. + Returns 0 on sucess or -1 otherwise. */ + extern int query_user_context(char ** list, + char ** newcon); + +/* Allow the user to manually enter a context as a fallback + if a list of authorized contexts could not be obtained. + Caller must free via freecon. + Returns 0 on success or -1 otherwise. */ + extern int manual_user_enter_context(const char *user, + char ** newcon); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/selinux/get_default_type.h b/include/selinux/get_default_type.h new file mode 100644 index 0000000..65c5dd4 --- /dev/null +++ b/include/selinux/get_default_type.h @@ -0,0 +1,23 @@ +/* get_default_type.h - contains header information and function prototypes + * for functions to get the default type for a role + */ + +#ifndef _SELINUX_GET_DEFAULT_TYPE_H_ +#define _SELINUX_GET_DEFAULT_TYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return path to default type file. */ + const char *selinux_default_type_path(void); + +/* Get the default type (domain) for 'role' and set 'type' to refer to it. + Caller must free via free(). + Return 0 on success or -1 otherwise. */ + int get_default_type(const char *role, char **type); + +#ifdef __cplusplus +} +#endif +#endif /* ifndef _GET_DEFAULT_TYPE_H_ */ diff --git a/include/selinux/label.h b/include/selinux/label.h new file mode 100644 index 0000000..277287e --- /dev/null +++ b/include/selinux/label.h @@ -0,0 +1,190 @@ +/* + * Labeling interface for userspace object managers and others. + * + * Author : Eamon Walsh + */ +#ifndef _SELABEL_H_ +#define _SELABEL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Opaque type used for all label handles. + */ + +struct selabel_handle; + +/* + * Available backends. + */ + +/* file contexts */ +#define SELABEL_CTX_FILE 0 +/* media contexts */ +#define SELABEL_CTX_MEDIA 1 +/* x contexts */ +#define SELABEL_CTX_X 2 +/* db objects */ +#define SELABEL_CTX_DB 3 +/* Android property service contexts */ +#define SELABEL_CTX_ANDROID_PROP 4 +/* Android service contexts */ +#define SELABEL_CTX_ANDROID_SERVICE 5 + +/* + * Available options + */ + +/* no-op option, useful for unused slots in an array of options */ +#define SELABEL_OPT_UNUSED 0 +/* validate contexts before returning them (boolean value) */ +#define SELABEL_OPT_VALIDATE 1 +/* don't use local customizations to backend data (boolean value) */ +#define SELABEL_OPT_BASEONLY 2 +/* specify an alternate path to use when loading backend data */ +#define SELABEL_OPT_PATH 3 +/* select a subset of the search space as an optimization (file backend) */ +#define SELABEL_OPT_SUBSET 4 +/* require a hash calculation on spec files */ +#define SELABEL_OPT_DIGEST 5 +/* total number of options */ +#define SELABEL_NOPT 6 + +/* + * Label operations + */ + +/** + * selabel_open - Create a labeling handle. + * @backend: one of the constants specifying a supported labeling backend. + * @opts: array of selabel_opt structures specifying label options or NULL. + * @nopts: number of elements in opts array or zero for no options. + * + * Open a labeling backend for use. The available backend identifiers are + * listed above. Options may be provided via the opts parameter; available + * options are listed above. Not all options may be supported by every + * backend. Return value is the created handle on success or NULL with + * @errno set on failure. + */ +struct selabel_handle *selabel_open(unsigned int backend, + const struct selinux_opt *opts, + unsigned nopts); + +/** + * selabel_close - Close a labeling handle. + * @handle: specifies handle to close + * + * Destroy the specified handle, closing files, freeing allocated memory, + * etc. The handle may not be further used after it has been closed. + */ +void selabel_close(struct selabel_handle *handle); + +/** + * selabel_lookup - Perform labeling lookup operation. + * @handle: specifies backend instance to query + * @con: returns the appropriate context with which to label the object + * @key: string input to lookup operation + * @type: numeric input to the lookup operation + * + * Perform a labeling lookup operation. Return %0 on success, -%1 with + * @errno set on failure. The key and type arguments are the inputs to the + * lookup operation; appropriate values are dictated by the backend in use. + * The result is returned in the memory pointed to by @con and must be freed + * by the user with freecon(). + */ +int selabel_lookup(struct selabel_handle *handle, char **con, + const char *key, int type); +int selabel_lookup_raw(struct selabel_handle *handle, char **con, + const char *key, int type); + +bool selabel_partial_match(struct selabel_handle *handle, const char *key); + +int selabel_lookup_best_match(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type); +int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type); + +/** + * selabel_digest - Retrieve the SHA1 digest and the list of specfiles used to + * generate the digest. The SELABEL_OPT_DIGEST option must + * be set in selabel_open() to initiate the digest generation. + * @handle: specifies backend instance to query + * @digest: returns a pointer to the SHA1 digest. + * @digest_len: returns length of digest in bytes. + * @specfiles: a list of specfiles used in the SHA1 digest generation. + * The list is NULL terminated and will hold @num_specfiles entries. + * @num_specfiles: number of specfiles in the list. + * + * Return %0 on success, -%1 with @errno set on failure. + */ +int selabel_digest(struct selabel_handle *rec, + unsigned char **digest, size_t *digest_len, + char ***specfiles, size_t *num_specfiles); + +enum selabel_cmp_result { + SELABEL_SUBSET, + SELABEL_EQUAL, + SELABEL_SUPERSET, + SELABEL_INCOMPARABLE +}; + +/** + * selabel_cmp - Compare two label configurations. + * @h1: handle for the first label configuration + * @h2: handle for the first label configuration + * + * Compare two label configurations. + * Return %SELABEL_SUBSET if @h1 is a subset of @h2, %SELABEL_EQUAL + * if @h1 is identical to @h2, %SELABEL_SUPERSET if @h1 is a superset + * of @h2, and %SELABEL_INCOMPARABLE if @h1 and @h2 are incomparable. + */ +enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, + struct selabel_handle *h2); + +/** + * selabel_stats - log labeling operation statistics. + * @handle: specifies backend instance to query + * + * Log a message with information about the number of queries performed, + * number of unused matching entries, or other operational statistics. + * Message is backend-specific, some backends may not output a message. + */ +void selabel_stats(struct selabel_handle *handle); + +/* + * Type codes used by specific backends + */ + +/* X backend */ +#define SELABEL_X_PROP 1 +#define SELABEL_X_EXT 2 +#define SELABEL_X_CLIENT 3 +#define SELABEL_X_EVENT 4 +#define SELABEL_X_SELN 5 +#define SELABEL_X_POLYPROP 6 +#define SELABEL_X_POLYSELN 7 + +/* DB backend */ +#define SELABEL_DB_DATABASE 1 +#define SELABEL_DB_SCHEMA 2 +#define SELABEL_DB_TABLE 3 +#define SELABEL_DB_COLUMN 4 +#define SELABEL_DB_SEQUENCE 5 +#define SELABEL_DB_VIEW 6 +#define SELABEL_DB_PROCEDURE 7 +#define SELABEL_DB_BLOB 8 +#define SELABEL_DB_TUPLE 9 +#define SELABEL_DB_LANGUAGE 10 +#define SELABEL_DB_EXCEPTION 11 +#define SELABEL_DB_DATATYPE 12 + +#ifdef __cplusplus +} +#endif +#endif /* _SELABEL_H_ */ diff --git a/include/selinux/restorecon.h b/include/selinux/restorecon.h new file mode 100644 index 0000000..595e772 --- /dev/null +++ b/include/selinux/restorecon.h @@ -0,0 +1,187 @@ +#ifndef _RESTORECON_H_ +#define _RESTORECON_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * selinux_restorecon - Relabel files. + * @pathname: specifies file/directory to relabel. + * @restorecon_flags: specifies the actions to be performed when relabeling. + * + * selinux_restorecon(3) will automatically call + * selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3) + * first time through to set the selabel_open(3) parameters to use the + * currently loaded policy file_contexts and request their computed digest. + * + * Should other selabel_open(3) parameters be required see + * selinux_restorecon_set_sehandle(3). + */ +extern int selinux_restorecon(const char *pathname, + unsigned int restorecon_flags); +/* + * restorecon_flags options + */ +/* + * Force the checking of labels even if the stored SHA1 + * digest matches the specfiles SHA1 digest. + */ +#define SELINUX_RESTORECON_IGNORE_DIGEST 0x0001 +/* + * Do not change file labels. + */ +#define SELINUX_RESTORECON_NOCHANGE 0x0002 +/* + * If set, change file label to that in spec file. + * If not, only change type component to that in spec file. + */ +#define SELINUX_RESTORECON_SET_SPECFILE_CTX 0x0004 +/* + * Recursively descend directories. + */ +#define SELINUX_RESTORECON_RECURSE 0x0008 +/* + * Log changes to selinux log. Note that if VERBOSE and + * PROGRESS are set, then PROGRESS will take precedence. + */ +#define SELINUX_RESTORECON_VERBOSE 0x0010 +/* + * If SELINUX_RESTORECON_PROGRESS is true and + * SELINUX_RESTORECON_MASS_RELABEL is true, then output approx % complete, + * else output the number of files in 1k blocks processed to stdout. + */ +#define SELINUX_RESTORECON_PROGRESS 0x0020 +/* + * Convert passed-in pathname to canonical pathname. + */ +#define SELINUX_RESTORECON_REALPATH 0x0040 +/* + * Prevent descending into directories that have a different + * device number than the pathname from which the descent began. + */ +#define SELINUX_RESTORECON_XDEV 0x0080 +/* + * Attempt to add an association between an inode and a specification. + * If there is already an association for the inode and it conflicts + * with the specification, then use the last matching specification. + */ +#define SELINUX_RESTORECON_ADD_ASSOC 0x0100 +/* + * Abort on errors during the file tree walk. + */ +#define SELINUX_RESTORECON_ABORT_ON_ERROR 0x0200 +/* + * Log any label changes to syslog. + */ +#define SELINUX_RESTORECON_SYSLOG_CHANGES 0x0400 +/* + * Log what spec matched each file. + */ +#define SELINUX_RESTORECON_LOG_MATCHES 0x0800 +/* + * Ignore files that do not exist. + */ +#define SELINUX_RESTORECON_IGNORE_NOENTRY 0x1000 +/* + * Do not read /proc/mounts to obtain a list of non-seclabel + * mounts to be excluded from relabeling checks. + */ +#define SELINUX_RESTORECON_IGNORE_MOUNTS 0x2000 +/* + * Set if there is a mass relabel required. + * See SELINUX_RESTORECON_PROGRESS flag for details. + */ +#define SELINUX_RESTORECON_MASS_RELABEL 0x4000 + +/** + * selinux_restorecon_set_sehandle - Set the global fc handle. + * @hndl: specifies handle to set as the global fc handle. + * + * Called by a process that has already called selabel_open(3) with it's + * required parameters, or if selinux_restorecon_default_handle(3) has been + * called to set the default selabel_open(3) parameters. + */ +extern void selinux_restorecon_set_sehandle(struct selabel_handle *hndl); + +/** + * selinux_restorecon_default_handle - Sets default selabel_open(3) parameters + * to use the currently loaded policy and + * file_contexts, also requests the digest. + * + * Return value is the created handle on success or NULL with @errno set on + * failure. + */ +extern struct selabel_handle *selinux_restorecon_default_handle(void); + +/** + * selinux_restorecon_set_exclude_list - Add a list of directories that are + * to be excluded from relabeling. + * @exclude_list: containing a NULL terminated list of one or more + * directories not to be relabeled. + */ +extern void selinux_restorecon_set_exclude_list(const char **exclude_list); + +/** + * selinux_restorecon_set_alt_rootpath - Use alternate rootpath. + * @alt_rootpath: containing the alternate rootpath to be used. + * + * Return %0 on success, -%1 with @errno set on failure. + */ +extern int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath); + +/** + * selinux_restorecon_xattr - Read/remove RESTORECON_LAST xattr entries. + * @pathname: specifies directory path to check. + * @xattr_flags: specifies the actions to be performed. + * @xattr_list: a linked list of struct dir_xattr structures containing + * the directory, digest and result of the action on the + * RESTORECON_LAST entry. + * + * selinux_restorecon_xattr(3) will automatically call + * selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3) + * first time through to set the selabel_open(3) parameters to use the + * currently loaded policy file_contexts and request their computed digest. + * + * Should other selabel_open(3) parameters be required see + * selinux_restorecon_set_sehandle(3), however note that a file_contexts + * computed digest is required for selinux_restorecon_xattr(). + */ +enum digest_result { + MATCH = 0, + NOMATCH, + DELETED_MATCH, + DELETED_NOMATCH, + ERROR +}; + +struct dir_xattr { + char *directory; + char *digest; /* A hex encoded string that can be printed. */ + enum digest_result result; + struct dir_xattr *next; +}; + +extern int selinux_restorecon_xattr(const char *pathname, + unsigned int xattr_flags, + struct dir_xattr ***xattr_list); + +/* + * xattr_flags options + */ +/* Recursively descend directories. */ +#define SELINUX_RESTORECON_XATTR_RECURSE 0x0001 +/* Delete non-matching digests from each directory in pathname. */ +#define SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS 0x0002 +/* Delete all digests found in pathname. */ +#define SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS 0x0004 +/* Do not read /proc/mounts. */ +#define SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS 0x0008 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/selinux/selinux.h b/include/selinux/selinux.h new file mode 100644 index 0000000..a34d54f --- /dev/null +++ b/include/selinux/selinux.h @@ -0,0 +1,679 @@ +#ifndef _SELINUX_H_ +#define _SELINUX_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */ +extern int is_selinux_enabled(void); +/* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */ +extern int is_selinux_mls_enabled(void); + +/* No longer used; here for compatibility with legacy callers. */ +typedef char *security_context_t; + +/* Free the memory allocated for a context by any of the below get* calls. */ +extern void freecon(char * con); + +/* Free the memory allocated for a context array by security_compute_user. */ +extern void freeconary(char ** con); + +/* Wrappers for the /proc/pid/attr API. */ + +/* Get current context, and set *con to refer to it. + Caller must free via freecon. */ +extern int getcon(char ** con); +extern int getcon_raw(char ** con); + +/* Set the current security context to con. + Note that use of this function requires that the entire application + be trusted to maintain any desired separation between the old and new + security contexts, unlike exec-based transitions performed via setexeccon. + When possible, decompose your application and use setexeccon()+execve() + instead. Note that the application may lose access to its open descriptors + as a result of a setcon() unless policy allows it to use descriptors opened + by the old context. */ +extern int setcon(const char * con); +extern int setcon_raw(const char * con); + +/* Get context of process identified by pid, and + set *con to refer to it. Caller must free via freecon. */ +extern int getpidcon(pid_t pid, char ** con); +extern int getpidcon_raw(pid_t pid, char ** con); + +/* Get previous context (prior to last exec), and set *con to refer to it. + Caller must free via freecon. */ +extern int getprevcon(char ** con); +extern int getprevcon_raw(char ** con); + +/* Get exec context, and set *con to refer to it. + Sets *con to NULL if no exec context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getexeccon(char ** con); +extern int getexeccon_raw(char ** con); + +/* Set exec security context for the next execve. + Call with NULL if you want to reset to the default. */ +extern int setexeccon(const char * con); +extern int setexeccon_raw(const char * con); + +/* Get fscreate context, and set *con to refer to it. + Sets *con to NULL if no fs create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getfscreatecon(char ** con); +extern int getfscreatecon_raw(char ** con); + +/* Set the fscreate security context for subsequent file creations. + Call with NULL if you want to reset to the default. */ +extern int setfscreatecon(const char * context); +extern int setfscreatecon_raw(const char * context); + +/* Get keycreate context, and set *con to refer to it. + Sets *con to NULL if no key create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getkeycreatecon(char ** con); +extern int getkeycreatecon_raw(char ** con); + +/* Set the keycreate security context for subsequent key creations. + Call with NULL if you want to reset to the default. */ +extern int setkeycreatecon(const char * context); +extern int setkeycreatecon_raw(const char * context); + +/* Get sockcreate context, and set *con to refer to it. + Sets *con to NULL if no socket create context has been set, i.e. using default. + If non-NULL, caller must free via freecon. */ +extern int getsockcreatecon(char ** con); +extern int getsockcreatecon_raw(char ** con); + +/* Set the sockcreate security context for subsequent socket creations. + Call with NULL if you want to reset to the default. */ +extern int setsockcreatecon(const char * context); +extern int setsockcreatecon_raw(const char * context); + +/* Wrappers for the xattr API. */ + +/* Get file context, and set *con to refer to it. + Caller must free via freecon. */ +extern int getfilecon(const char *path, char ** con); +extern int getfilecon_raw(const char *path, char ** con); +extern int lgetfilecon(const char *path, char ** con); +extern int lgetfilecon_raw(const char *path, char ** con); +extern int fgetfilecon(int fd, char ** con); +extern int fgetfilecon_raw(int fd, char ** con); + +/* Set file context */ +extern int setfilecon(const char *path, const char * con); +extern int setfilecon_raw(const char *path, const char * con); +extern int lsetfilecon(const char *path, const char * con); +extern int lsetfilecon_raw(const char *path, const char * con); +extern int fsetfilecon(int fd, const char * con); +extern int fsetfilecon_raw(int fd, const char * con); + +/* Wrappers for the socket API */ + +/* Get context of peer socket, and set *con to refer to it. + Caller must free via freecon. */ +extern int getpeercon(int fd, char ** con); +extern int getpeercon_raw(int fd, char ** con); + +/* Wrappers for the selinuxfs (policy) API. */ + +typedef unsigned int access_vector_t; +typedef unsigned short security_class_t; + +struct av_decision { + access_vector_t allowed; + access_vector_t decided; + access_vector_t auditallow; + access_vector_t auditdeny; + unsigned int seqno; + unsigned int flags; +}; + +/* Definitions of av_decision.flags */ +#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 + +/* Structure for passing options, used by AVC and label subsystems */ +struct selinux_opt { + int type; + const char *value; +}; + +/* Callback facilities */ +union selinux_callback { + /* log the printf-style format and arguments, + with the type code indicating the type of message */ + int +#ifdef __GNUC__ +__attribute__ ((format(printf, 2, 3))) +#endif + (*func_log) (int type, const char *fmt, ...); + /* store a string representation of auditdata (corresponding + to the given security class) into msgbuf. */ + int (*func_audit) (void *auditdata, security_class_t cls, + char *msgbuf, size_t msgbufsize); + /* validate the supplied context, modifying if necessary */ + int (*func_validate) (char **ctx); + /* netlink callback for setenforce message */ + int (*func_setenforce) (int enforcing); + /* netlink callback for policyload message */ + int (*func_policyload) (int seqno); +}; + +#define SELINUX_CB_LOG 0 +#define SELINUX_CB_AUDIT 1 +#define SELINUX_CB_VALIDATE 2 +#define SELINUX_CB_SETENFORCE 3 +#define SELINUX_CB_POLICYLOAD 4 + +extern union selinux_callback selinux_get_callback(int type); +extern void selinux_set_callback(int type, union selinux_callback cb); + + /* Logging type codes, passed to the logging callback */ +#define SELINUX_ERROR 0 +#define SELINUX_WARNING 1 +#define SELINUX_INFO 2 +#define SELINUX_AVC 3 +#define SELINUX_TRANS_DIR "/var/run/setrans" + +/* Compute an access decision. */ +extern int security_compute_av(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); +extern int security_compute_av_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); + +extern int security_compute_av_flags(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); +extern int security_compute_av_flags_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd); + +/* Compute a labeling decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_create(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_create_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_create_name(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon); +extern int security_compute_create_name_raw(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon); + +/* Compute a relabeling decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_relabel(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_relabel_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); + +/* Compute a polyinstantiation member decision and set *newcon to refer to it. + Caller must free via freecon. */ +extern int security_compute_member(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); +extern int security_compute_member_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon); + +/* Compute the set of reachable user contexts and set *con to refer to + the NULL-terminated array of contexts. Caller must free via freeconary. */ +extern int security_compute_user(const char * scon, + const char *username, + char *** con); +extern int security_compute_user_raw(const char * scon, + const char *username, + char *** con); + +/* Load a policy configuration. */ +extern int security_load_policy(void *data, size_t len); + +/* Get the context of an initial kernel security identifier by name. + Caller must free via freecon */ +extern int security_get_initial_context(const char *name, + char ** con); +extern int security_get_initial_context_raw(const char *name, + char ** con); + +/* + * Make a policy image and load it. + * This function provides a higher level interface for loading policy + * than security_load_policy, internally determining the right policy + * version, locating and opening the policy file, mapping it into memory, + * manipulating it as needed for current boolean settings and/or local + * definitions, and then calling security_load_policy to load it. + * + * 'preservebools' is a boolean flag indicating whether current + * policy boolean values should be preserved into the new policy (if 1) + * or reset to the saved policy settings (if 0). The former case is the + * default for policy reloads, while the latter case is an option for policy + * reloads but is primarily for the initial policy load. + */ +extern int selinux_mkload_policy(int preservebools); + +/* + * Perform the initial policy load. + * This function determines the desired enforcing mode, sets the + * the *enforce argument accordingly for the caller to use, sets the + * SELinux kernel enforcing status to match it, and loads the policy. + * It also internally handles the initial selinuxfs mount required to + * perform these actions. + * + * The function returns 0 if everything including the policy load succeeds. + * In this case, init is expected to re-exec itself in order to transition + * to the proper security context. + * Otherwise, the function returns -1, and init must check *enforce to + * determine how to proceed. If enforcing (*enforce > 0), then init should + * halt the system. Otherwise, init may proceed normally without a re-exec. + */ +extern int selinux_init_load_policy(int *enforce); + +/* Translate boolean strict to name value pair. */ +typedef struct { + char *name; + int value; +} SELboolean; +/* save a list of booleans in a single transaction. */ +extern int security_set_boolean_list(size_t boolcnt, + SELboolean * boollist, int permanent); + +/* Load policy boolean settings. + Path may be NULL, in which case the booleans are loaded from + the active policy boolean configuration file. */ +extern int security_load_booleans(char *path); + +/* Check the validity of a security context. */ +extern int security_check_context(const char * con); +extern int security_check_context_raw(const char * con); + +/* Canonicalize a security context. */ +extern int security_canonicalize_context(const char * con, + char ** canoncon); +extern int security_canonicalize_context_raw(const char * con, + char ** canoncon); + +/* Get the enforce flag value. */ +extern int security_getenforce(void); + +/* Set the enforce flag value. */ +extern int security_setenforce(int value); + +/* Get the load-time behavior for undefined classes/permissions */ +extern int security_reject_unknown(void); + +/* Get the runtime behavior for undefined classes/permissions */ +extern int security_deny_unknown(void); + +/* Get the checkreqprot value */ +extern int security_get_checkreqprot(void); + +/* Disable SELinux at runtime (must be done prior to initial policy load). */ +extern int security_disable(void); + +/* Get the policy version number. */ +extern int security_policyvers(void); + +/* Get the boolean names */ +extern int security_get_boolean_names(char ***names, int *len); + +/* Get the pending value for the boolean */ +extern int security_get_boolean_pending(const char *name); + +/* Get the active value for the boolean */ +extern int security_get_boolean_active(const char *name); + +/* Set the pending value for the boolean */ +extern int security_set_boolean(const char *name, int value); + +/* Commit the pending values for the booleans */ +extern int security_commit_booleans(void); + +/* Userspace class mapping support */ +struct security_class_mapping { + const char *name; + const char *perms[sizeof(access_vector_t) * 8 + 1]; +}; + +/** + * selinux_set_mapping - Enable dynamic mapping between integer offsets and security class names + * @map: array of security_class_mapping structures + * + * The core avc_has_perm() API uses integers to represent security + * classes; previous to the introduction of this function, it was + * common for userspace object managers to be compiled using generated + * offsets for a particular policy. However, that strongly ties the build of the userspace components to a particular policy. + * + * By using this function to map between integer offsets and security + * class names, it's possible to replace a system policies that have + * at least the same set of security class names as used by the + * userspace object managers. + * + * To correctly use this function, you should override the generated + * security class defines from the system policy in a local header, + * starting at 1, and have one security_class_mapping structure entry + * per define. + */ +extern int selinux_set_mapping(struct security_class_mapping *map); + +/* Common helpers */ + +/* Convert between mode and security class values */ +extern security_class_t mode_to_security_class(mode_t mode); +/* Convert between security class values and string names */ +extern security_class_t string_to_security_class(const char *name); +extern const char *security_class_to_string(security_class_t cls); + +/* Convert between individual access vector permissions and string names */ +extern const char *security_av_perm_to_string(security_class_t tclass, + access_vector_t perm); +extern access_vector_t string_to_av_perm(security_class_t tclass, + const char *name); + +/* Returns an access vector in a string representation. User must free the + * returned string via free(). */ +extern int security_av_string(security_class_t tclass, + access_vector_t av, char **result); + +/* Display an access vector in a string representation. */ +extern void print_access_vector(security_class_t tclass, access_vector_t av); + +/* Set the function used by matchpathcon_init when displaying + errors about the file_contexts configuration. If not set, + then this defaults to fprintf(stderr, fmt, ...). */ +extern void set_matchpathcon_printf(void (*f) (const char *fmt, ...)); + +/* Set the function used by matchpathcon_init when checking the + validity of a context in the file contexts configuration. If not set, + then this defaults to a test based on security_check_context(). + The function is also responsible for reporting any such error, and + may include the 'path' and 'lineno' in such error messages. */ +extern void set_matchpathcon_invalidcon(int (*f) (const char *path, + unsigned lineno, + char *context)); + +/* Same as above, but also allows canonicalization of the context, + by changing *context to refer to the canonical form. If not set, + and invalidcon is also not set, then this defaults to calling + security_canonicalize_context(). */ +extern void set_matchpathcon_canoncon(int (*f) (const char *path, + unsigned lineno, + char **context)); + +/* Set flags controlling operation of matchpathcon_init or matchpathcon. */ +#define MATCHPATHCON_BASEONLY 1 /* Only process the base file_contexts file. */ +#define MATCHPATHCON_NOTRANS 2 /* Do not perform any context translation. */ +#define MATCHPATHCON_VALIDATE 4 /* Validate/canonicalize contexts at init time. */ +extern void set_matchpathcon_flags(unsigned int flags); + +/* Load the file contexts configuration specified by 'path' + into memory for use by subsequent matchpathcon calls. + If 'path' is NULL, then load the active file contexts configuration, + i.e. the path returned by selinux_file_context_path(). + Unless the MATCHPATHCON_BASEONLY flag has been set, this + function also checks for a 'path'.homedirs file and + a 'path'.local file and loads additional specifications + from them if present. */ +extern int matchpathcon_init(const char *path); + +/* Same as matchpathcon_init, but only load entries with + regexes that have stems that are prefixes of 'prefix'. */ +extern int matchpathcon_init_prefix(const char *path, const char *prefix); + +/* Free the memory allocated by matchpathcon_init. */ +extern void matchpathcon_fini(void); + +/* Resolve all of the symlinks and relative portions of a pathname, but NOT + * the final component (same a realpath() unless the final component is a + * symlink. Resolved path must be a path of size PATH_MAX + 1 */ +extern int realpath_not_final(const char *name, char *resolved_path); + +/* Match the specified pathname and mode against the file contexts + configuration and set *con to refer to the resulting context. + 'mode' can be 0 to disable mode matching. + Caller must free via freecon. + If matchpathcon_init has not already been called, then this function + will call it upon its first invocation with a NULL path. */ +extern int matchpathcon(const char *path, + mode_t mode, char ** con); + +/* Same as above, but return a specification index for + later use in a matchpathcon_filespec_add() call - see below. */ +extern int matchpathcon_index(const char *path, + mode_t mode, char ** con); + +/* Maintain an association between an inode and a specification index, + and check whether a conflicting specification is already associated + with the same inode (e.g. due to multiple hard links). If so, then + use the latter of the two specifications based on their order in the + file contexts configuration. Return the used specification index. */ +extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file); + +/* Destroy any inode associations that have been added, e.g. to restart + for a new filesystem. */ +extern void matchpathcon_filespec_destroy(void); + +/* Display statistics on the hash table usage for the associations. */ +extern void matchpathcon_filespec_eval(void); + +/* Check to see whether any specifications had no matches and report them. + The 'str' is used as a prefix for any warning messages. */ +extern void matchpathcon_checkmatches(char *str); + +/* Match the specified media and against the media contexts + configuration and set *con to refer to the resulting context. + Caller must free con via freecon. */ +extern int matchmediacon(const char *media, char ** con); + +/* + selinux_getenforcemode reads the /etc/selinux/config file and determines + whether the machine should be started in enforcing (1), permissive (0) or + disabled (-1) mode. + */ +extern int selinux_getenforcemode(int *enforce); + +/* + selinux_boolean_sub reads the /etc/selinux/TYPE/booleans.subs_dist file + looking for a record with boolean_name. If a record exists selinux_boolean_sub + returns the translated name otherwise it returns the original name. + The returned value needs to be freed. On failure NULL will be returned. + */ +extern char *selinux_boolean_sub(const char *boolean_name); + +/* + selinux_getpolicytype reads the /etc/selinux/config file and determines + what the default policy for the machine is. Calling application must + free policytype. + */ +extern int selinux_getpolicytype(char **policytype); + +/* + selinux_policy_root reads the /etc/selinux/config file and returns + the directory path under which the compiled policy file and context + configuration files exist. + */ +extern const char *selinux_policy_root(void); + +/* + selinux_set_policy_root sets an alternate policy root directory path under + which the compiled policy file and context configuration files exist. + */ +extern int selinux_set_policy_root(const char *rootpath); + +/* These functions return the paths to specific files under the + policy root directory. */ +extern const char *selinux_current_policy_path(void); +extern const char *selinux_binary_policy_path(void); +extern const char *selinux_failsafe_context_path(void); +extern const char *selinux_removable_context_path(void); +extern const char *selinux_default_context_path(void); +extern const char *selinux_user_contexts_path(void); +extern const char *selinux_file_context_path(void); +extern const char *selinux_file_context_homedir_path(void); +extern const char *selinux_file_context_local_path(void); +extern const char *selinux_file_context_subs_path(void); +extern const char *selinux_file_context_subs_dist_path(void); +extern const char *selinux_homedir_context_path(void); +extern const char *selinux_media_context_path(void); +extern const char *selinux_virtual_domain_context_path(void); +extern const char *selinux_virtual_image_context_path(void); +extern const char *selinux_lxc_contexts_path(void); +extern const char *selinux_x_context_path(void); +extern const char *selinux_sepgsql_context_path(void); +extern const char *selinux_openrc_contexts_path(void); +extern const char *selinux_openssh_contexts_path(void); +extern const char *selinux_snapperd_contexts_path(void); +extern const char *selinux_systemd_contexts_path(void); +extern const char *selinux_contexts_path(void); +extern const char *selinux_securetty_types_path(void); +extern const char *selinux_booleans_subs_path(void); +extern const char *selinux_booleans_path(void); +extern const char *selinux_customizable_types_path(void); +extern const char *selinux_users_path(void); +extern const char *selinux_usersconf_path(void); +extern const char *selinux_translations_path(void); +extern const char *selinux_colors_path(void); +extern const char *selinux_netfilter_context_path(void); +extern const char *selinux_path(void); + +/** + * selinux_check_access - Check permissions and perform appropriate auditing. + * @scon: source security context + * @tcon: target security context + * @tclass: target security class string + * @perm: requested permissions string, interpreted based on @tclass + * @auditdata: auxiliary audit data + * + * Check the AVC to determine whether the @perm permissions are granted + * for the SID pair (@scon, @tcon), interpreting the permissions + * based on @tclass. + * Return %0 if all @perm permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied or to another + * value upon other errors. + * If auditing or logging is configured the appropriate callbacks will be called + * and passed the auditdata field + */ +extern int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata); + +/* Check a permission in the passwd class. + Return 0 if granted or -1 otherwise. */ +extern int selinux_check_passwd_access(access_vector_t requested); +extern int checkPasswdAccess(access_vector_t requested); + +/* Check if the tty_context is defined as a securetty + Return 0 if secure, < 0 otherwise. */ +extern int selinux_check_securetty_context(const char * tty_context); + +/* Set the path to the selinuxfs mount point explicitly. + Normally, this is determined automatically during libselinux + initialization, but this is not always possible, e.g. for /sbin/init + which performs the initial mount of selinuxfs. */ +void set_selinuxmnt(const char *mnt); + +/* Check if selinuxfs exists as a kernel filesystem */ +int selinuxfs_exists(void); + +/* clear selinuxmnt variable and free allocated memory */ +void fini_selinuxmnt(void); + +/* Set an appropriate security context based on the filename of a helper + * program, falling back to a new context with the specified type. */ +extern int setexecfilecon(const char *filename, const char *fallback_type); + +#ifndef DISABLE_RPM +/* Execute a helper for rpm in an appropriate security context. */ +extern int rpm_execcon(unsigned int verified, + const char *filename, + char *const argv[], char *const envp[]); +#endif + +/* Returns whether a file context is customizable, and should not + be relabeled . */ +extern int is_context_customizable(const char * scontext); + +/* Perform context translation between the human-readable format + ("translated") and the internal system format ("raw"). + Caller must free the resulting context via freecon. + Returns -1 upon an error or 0 otherwise. + If passed NULL, sets the returned context to NULL and returns 0. */ +extern int selinux_trans_to_raw_context(const char * trans, + char ** rawp); +extern int selinux_raw_to_trans_context(const char * raw, + char ** transp); + +/* Perform context translation between security contexts + and display colors. Returns a space-separated list of ten + ten hex RGB triples prefixed by hash marks, e.g. "#ff0000". + Caller must free the resulting string via free. + Returns -1 upon an error or 0 otherwise. */ +extern int selinux_raw_context_to_color(const char * raw, + char **color_str); + +/* Get the SELinux username and level to use for a given Linux username. + These values may then be passed into the get_ordered_context_list* + and get_default_context* functions to obtain a context for the user. + Returns 0 on success or -1 otherwise. + Caller must free the returned strings via free. */ +extern int getseuserbyname(const char *linuxuser, char **seuser, char **level); + +/* Get the SELinux username and level to use for a given Linux username and service. + These values may then be passed into the get_ordered_context_list* + and get_default_context* functions to obtain a context for the user. + Returns 0 on success or -1 otherwise. + Caller must free the returned strings via free. */ +extern int getseuser(const char *username, const char *service, + char **r_seuser, char **r_level); + +/* Compare two file contexts, return 0 if equivalent. */ +extern int selinux_file_context_cmp(const char * a, + const char * b); + +/* + * Verify the context of the file 'path' against policy. + * Return 1 if match, 0 if not and -1 on error. + */ +extern int selinux_file_context_verify(const char *path, mode_t mode); + +/* This function sets the file context on to the system defaults returns 0 on success */ +extern int selinux_lsetfilecon_default(const char *path); + +/* + * Force a reset of the loaded configuration + * WARNING: This is not thread safe. Be very sure that no other threads + * are calling into libselinux when this is called. + */ +extern void selinux_reset_config(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 0000000..4b3626d --- /dev/null +++ b/man/Makefile @@ -0,0 +1,38 @@ +# Installation directories. +LINGUAS ?= ru +PREFIX ?= /usr +MANDIR ?= $(PREFIX)/share/man +MAN3SUBDIR ?= man3 +MAN5SUBDIR ?= man5 +MAN8SUBDIR ?= man8 +MAN3DIR ?= $(MANDIR)/$(MAN3SUBDIR) +MAN5DIR ?= $(MANDIR)/$(MAN5SUBDIR) +MAN8DIR ?= $(MANDIR)/$(MAN8SUBDIR) + +all: + +install: all + mkdir -p $(DESTDIR)$(MAN3DIR) + mkdir -p $(DESTDIR)$(MAN5DIR) + mkdir -p $(DESTDIR)$(MAN8DIR) + install -m 644 man3/*.3 $(DESTDIR)$(MAN3DIR) + install -m 644 man5/*.5 $(DESTDIR)$(MAN5DIR) + install -m 644 man8/*.8 $(DESTDIR)$(MAN8DIR) + for lang in $(LINGUAS) ; do \ + if [ -e $${lang}/man3 ] ; then \ + mkdir -p $(DESTDIR)$(MANDIR)/$${lang}/$(MAN3SUBDIR) ; \ + install -m 644 $${lang}/man3/*.3 $(DESTDIR)$(MANDIR)/$${lang}/$(MAN3SUBDIR) ; \ + fi ; \ + if [ -e $${lang}/man5 ] ; then \ + mkdir -p $(DESTDIR)$(MANDIR)/$${lang}/$(MAN5SUBDIR) ; \ + install -m 644 $${lang}/man5/*.5 $(DESTDIR)$(MANDIR)/$${lang}/$(MAN5SUBDIR) ; \ + fi ; \ + if [ -e $${lang}/man8 ] ; then \ + mkdir -p $(DESTDIR)$(MANDIR)/$${lang}/$(MAN8SUBDIR) ; \ + install -m 644 $${lang}/man8/*.8 $(DESTDIR)$(MANDIR)/$${lang}/$(MAN8SUBDIR) ; \ + fi ; \ + done + +relabel: + +indent distclean clean: diff --git a/man/man3/avc_add_callback.3 b/man/man3/avc_add_callback.3 new file mode 100644 index 0000000..bdbbadf --- /dev/null +++ b/man/man3/avc_add_callback.3 @@ -0,0 +1,192 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_add_callback" "3" "9 June 2004" "" "SELinux API documentation" +.SH "NAME" +avc_add_callback \- additional event notification for SELinux userspace object managers +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_add_callback(int (*" callback ")(uint32_t " event , +.in +\w'int avc_add_callback(int (*callback)('u +.BI "security_id_t " ssid , +.br +.BI "security_id_t " tsid , +.br +.BI "security_class_t " tclass , +.br +.BI "access_vector_t " perms , +.br +.BI "access_vector_t *" out_retained ")," +.in +.in +\w'int avc_add_callback('u +.BI "uint32_t " events ", security_id_t " ssid , +.br +.BI "security_id_t " tsid ", security_class_t " tclass , +.br +.BI "access_vector_t " perms ");" +.in +. +.SH "DESCRIPTION" +.BR avc_add_callback () +is used to register callback functions on security events. The purpose of this functionality is to allow userspace object managers to take additional action when a policy change, usually a policy reload, causes permissions to be granted or revoked. + +.I events +is the +.RI bitwise- or +of security events on which to register the callback; see +.B SECURITY EVENTS +below. + +.IR ssid , +.IR tsid , +.IR tclass , +and +.I perms +specify the source and target SID's, target class, and specific permissions that the callback wishes to monitor. The special symbol +.B SECSID_WILD +may be passed as the +.I source +or +.I target +and will cause any SID to match. + +.I callback +is the callback function provided by the userspace object manager. The +.I event +argument indicates the security event which occurred; the remaining arguments +are interpreted according to the event as described below. The return value +of the callback should be zero on success, \-1 on error with +.I errno +set appropriately (but see +.B RETURN VALUE +below). +. +.SH "SECURITY EVENTS" +In all cases below, +.I ssid +and/or +.I tsid +may be set to +.BR SECSID_WILD , +indicating that the change applies to all source and/or target SID's. Unless otherwise indicated, the +.I out_retained +parameter is unused. +. +.TP +.B AVC_CALLBACK_GRANT +Previously denied permissions are now granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to grant. +.TP +.B AVC_CALLBACK_TRY_REVOKE +Previously granted permissions are now conditionally revoked for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to revoke. The callback should set +.I out_retained +to the subset of +.I perms +which are retained as migrated permissions. Note that +.I out_retained +is ignored if the callback returns \-1. +.TP +.B AVC_CALLBACK_REVOKE +Previously granted permissions are now unconditionally revoked for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.I perms +indicates the permissions to revoke. +.TP +.B AVC_CALLBACK_RESET +Indicates that the cache was flushed. The SID, class, and permission arguments are unused and are set to NULL. +.TP +.B AVC_CALLBACK_AUDITALLOW_ENABLE +The permissions given by +.I perms +should now be audited when granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITALLOW_DISABLE +The permissions given by +.I perms +should no longer be audited when granted for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITDENY_ENABLE +The permissions given by +.I perms +should now be audited when denied for +.IR ssid , +.I tsid +with respect to +.IR tclass . +.TP +.B AVC_CALLBACK_AUDITDENY_DISABLE +The permissions given by +.I perms +should no longer be audited when denied for +.IR ssid , +.I tsid +with respect to +.IR tclass . +. +.SH "RETURN VALUE" +On success, +.BR avc_add_callback () +returns zero. On error, \-1 is returned and +.I errno +is set appropriately. + +A return value of \-1 from a callback is interpreted as a failed policy operation. If such a return value is encountered, all remaining callbacks registered on the event are called. In threaded mode, the netlink handler thread may then terminate and cause the userspace AVC to return +.B EINVAL +on all further permission checks until +.BR avc_destroy (3) +is called. In non-threaded mode, the permission check on which the error occurred will return \-1 and the value of +.I errno +encountered to the caller. In both cases, a log message is produced and the kernel may be notified of the error. +. +.SH "ERRORS" +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "NOTES" +If the userspace AVC is running in threaded mode, callbacks registered via +.BR avc_add_callback () +may be executed in the context of the netlink handler thread. This will likely introduce synchronization issues requiring the use of locks. See +.BR avc_init (3). + +Support for dynamic revocation and retained permissions is mostly unimplemented in the SELinux kernel module. The only security event that currently gets exercised is +.BR AVC_CALLBACK_RESET . +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR security_compute_av (3) +.BR selinux (8) diff --git a/man/man3/avc_audit.3 b/man/man3/avc_audit.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/man/man3/avc_audit.3 @@ -0,0 +1 @@ +.so man3/avc_has_perm.3 diff --git a/man/man3/avc_av_stats.3 b/man/man3/avc_av_stats.3 new file mode 100644 index 0000000..6732dc1 --- /dev/null +++ b/man/man3/avc_av_stats.3 @@ -0,0 +1 @@ +.so man3/avc_cache_stats.3 diff --git a/man/man3/avc_cache_stats.3 b/man/man3/avc_cache_stats.3 new file mode 100644 index 0000000..c00f090 --- /dev/null +++ b/man/man3/avc_cache_stats.3 @@ -0,0 +1,103 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_cache_stats" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_cache_stats, avc_av_stats, avc_sid_stats \- obtain userspace SELinux AVC statistics +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "void avc_av_stats(void);" +.sp +.BI "void avc_sid_stats(void);" +.sp +.BI "void avc_cache_stats(struct avc_cache_stats *" stats ");" +. +.SH "DESCRIPTION" +The userspace AVC maintains two internal hash tables, one to store security ID's and one to cache access decisions. + +.BR avc_av_stats () +and +.BR avc_sid_stats () +produce log messages indicating the status of the access decision and SID tables, respectively. The messages contain the number of entries in the table, number of hash buckets and number of buckets used, and maximum number of entries in a single bucket. + +.BR avc_cache_stats () +populates a structure whose fields reflect cache activity: + +.RS +.ta 4n 14n +.nf +struct avc_cache_stats { + unsigned entry_lookups; + unsigned entry_hits; + unsigned entry_misses; + unsigned entry_discards; + unsigned cav_lookups; + unsigned cav_hits; + unsigned cav_probes; + unsigned cav_misses; +}; +.fi +.ta +.RE + +.TP +.I entry_lookups +Number of queries made. +.TP +.I entry_hits +Number of times a decision was found in the +.I aeref +argument. +.TP +.I entry_misses +Number of times a decision was not found in the +.I aeref +argument. +.TP +.I entry_discards +Number of times a decision was not found in the +.I aeref +argument and the +.I aeref +argument was non-NULL. +.TP +.I cav_lookups +Number of cache lookups. +.TP +.I cav_hits +Number of cache hits. +.TP +.I cav_misses +Number of cache misses. +.TP +.I cav_probes +Number of entries examined while searching the cache. +. +.SH "NOTES" +When the cache is flushed as a result of a call to +.BR avc_reset () +or a policy change notification, +the statistics returned by +.BR avc_cache_stats () +are reset to zero. The SID table, however, is left +unchanged. + +When a policy change notification is received, a call to +.BR avc_av_stats () +is made before the cache is flushed. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_add_callback (3), +.BR selinux (8) diff --git a/man/man3/avc_cleanup.3 b/man/man3/avc_cleanup.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/man/man3/avc_cleanup.3 @@ -0,0 +1 @@ +.so man3/avc_open.3 diff --git a/man/man3/avc_compute_create.3 b/man/man3/avc_compute_create.3 new file mode 100644 index 0000000..ce615bf --- /dev/null +++ b/man/man3/avc_compute_create.3 @@ -0,0 +1,64 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "avc_compute_create" "3" "30 Mar 2007" "" "SELinux API documentation" +.SH "NAME" +avc_compute_create, avc_compute_member \- obtain SELinux label for new object +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_compute_create(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_compute_create('u +.BI "security_class_t " tclass ", security_id_t *" newsid ");" +.sp +.in +.BI "int avc_compute_member(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_compute_member('u +.BI "security_class_t " tclass ", security_id_t *" newsid ");" +.in +. +.SH "DESCRIPTION" +.BR avc_compute_create () +is used to compute a SID to use for labeling a new object in a particular class based on a SID pair. This call is identical to +.BR security_compute_create (), +but does not require converting from userspace SID's to contexts and back again. + +.BR avc_compute_member () +is used to compute a SID to use for labeling a polyinstantiated object instance of a particular class based on a SID pair. This call is identical to +.BR security_compute_member (), +but does not require converting from userspace SID's to contexts and back again. + +These functions +return a SID for the computed context in the memory referenced by +.IR sid . +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +The +.I tclass +and/or the security contexts referenced by +.I ssid +and +.I tsid +are not recognized by the currently loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR avc_init (3), +.BR avc_context_to_sid (3), +.BR security_compute_create (3), +.BR selinux (8) diff --git a/man/man3/avc_compute_member.3 b/man/man3/avc_compute_member.3 new file mode 100644 index 0000000..28307ce --- /dev/null +++ b/man/man3/avc_compute_member.3 @@ -0,0 +1 @@ +.so man3/avc_compute_create.3 diff --git a/man/man3/avc_context_to_sid.3 b/man/man3/avc_context_to_sid.3 new file mode 100644 index 0000000..5532d6c --- /dev/null +++ b/man/man3/avc_context_to_sid.3 @@ -0,0 +1,73 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_context_to_sid" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_context_to_sid, avc_sid_to_context, avc_get_initial_sid \- obtain and manipulate SELinux security ID's +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_context_to_sid(char *" ctx ", security_id_t *" sid ");" +.sp +.BI "int avc_sid_to_context(security_id_t " sid ", char **" ctx ");" +.sp +.BI "int avc_get_initial_sid(const char *" name ", security_id_t *" sid ");" +. +.SH "DESCRIPTION" +Security ID's (SID's) are opaque representations of security contexts, managed by the userspace AVC. + +.BR avc_context_to_sid () +returns a SID for the given +.I context +in the memory referenced by +.IR sid . + +.BR avc_sid_to_context () +returns a copy of the context represented by +.I sid +in the memory referenced by +.IR ctx . +The user must free the copy with +.BR freecon (3). + +.BR avc_get_initial_sid () +returns a SID for the kernel initial security identifier specified by +.IR name . +. +.SH "RETURN VALUE" +.BR avc_context_to_sid () +and +.BR avc_sid_to_context () +return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOMEM +An attempt to allocate memory failed. +.SH "NOTES" +As of libselinux version 2.0.86, SID's are no longer reference counted. A SID will be valid from the time it is first obtained until the next call to +.BR avc_destroy (3). +The +.BR sidget (3) +and +.BR sidput (3) +functions, formerly used to adjust the reference count, are no-ops and are deprecated. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_has_perm (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR getcon (3), +.BR freecon (3), +.BR selinux (8) diff --git a/man/man3/avc_destroy.3 b/man/man3/avc_destroy.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/man/man3/avc_destroy.3 @@ -0,0 +1 @@ +.so man3/avc_open.3 diff --git a/man/man3/avc_entry_ref_init.3 b/man/man3/avc_entry_ref_init.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/man/man3/avc_entry_ref_init.3 @@ -0,0 +1 @@ +.so man3/avc_has_perm.3 diff --git a/man/man3/avc_get_initial_context.3 b/man/man3/avc_get_initial_context.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/man/man3/avc_get_initial_context.3 @@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3 diff --git a/man/man3/avc_get_initial_sid.3 b/man/man3/avc_get_initial_sid.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/man/man3/avc_get_initial_sid.3 @@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3 diff --git a/man/man3/avc_has_perm.3 b/man/man3/avc_has_perm.3 new file mode 100644 index 0000000..3e9fca8 --- /dev/null +++ b/man/man3/avc_has_perm.3 @@ -0,0 +1,159 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_has_perm" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_has_perm, avc_has_perm_noaudit, avc_audit, avc_entry_ref_init \- obtain and audit SELinux access decisions +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "void avc_entry_ref_init(struct avc_entry_ref *" aeref ");" +.sp +.BI "int avc_has_perm(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_has_perm('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct avc_entry_ref *" aeref ", void *" auditdata ");" +.in +.sp +.BI "int avc_has_perm_noaudit(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_has_perm('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct avc_entry_ref *" aeref ", struct av_decision *" avd ");" +.in +.sp +.BI "void avc_audit(security_id_t " ssid ", security_id_t " tsid , +.in +\w'void avc_audit('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct av_decision *" avd ", int " result ", void *" auditdata ");" +.in +. +.SH "DESCRIPTION" +.BR avc_entry_ref_init () +initializes an +.B avc_entry_ref +structure; see +.B ENTRY REFERENCES +below. This function may be implemented as a macro. + +.BR avc_has_perm () +checks whether the +.I requested +permissions are granted +for subject SID +.IR ssid +and target SID +.IR tsid , +interpreting the permissions +based on +.I tclass +and updating +.IR aeref , +if non-NULL, to refer to a cache entry with the resulting decision. The granting or denial of permissions is audited in accordance with the policy. The +.I auditdata +parameter is for supplemental auditing; see +.BR avc_audit () +below. + +.BR avc_has_perm_noaudit () +behaves as +.BR avc_has_perm () +without producing an audit message. The access decision is returned in +.I avd +and can be passed to +.BR avc_audit () +explicitly. + +.BR avc_audit () +produces an audit message for the access query represented by +.IR ssid , +.IR tsid , +.IR tclass , +and +.IR requested , +with a decision represented by +.IR avd . +Pass the value returned by +.BR avc_has_perm_noaudit () +as +.IR result . +The +.I auditdata +parameter is passed to the user-supplied +.B func_audit +callback and can be used to add supplemental information to the audit message; see +.BR avc_init (3). +. +.SH "ENTRY REFERENCES" +Entry references can be used to speed cache performance for repeated queries on the same subject and target. The userspace AVC will check the +.I aeref +argument, if supplied, before searching the cache on a permission query. After a query is performed, +.I aeref +will be updated to reference the cache entry for that query. A subsequent query on the same subject and target will then have the decision at hand without having to walk the cache. + +After declaring an +.B avc_entry_ref +structure, use +.BR avc_entry_ref_init () +to initialize it before passing it to +.BR avc_has_perm () +or +.BR \%avc_has_perm_noaudit () +for the first time. +Using an uninitialized structure will produce undefined behavior. +. +.SH "RETURN VALUE" +If requested permissions are granted, zero is returned. If requested permissions are denied or an error occurred, \-1 is returned and +.I errno +is set appropriately. + +In permissive mode, zero will be returned and +.I errno +unchanged even if permissions were denied. +.BR avc_has_perm () +will still produce an audit message in this case. +. +.SH "ERRORS" +.TP +.B EACCES +A requested permission was denied. +.TP +.B EINVAL +The +.I tclass +and/or the security contexts referenced by +.I ssid +and +.I tsid +are not recognized by the currently loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "NOTES" +Internal errors encountered by the userspace AVC may cause certain values of +.I errno +to be returned unexpectedly. For example, netlink socket errors may produce +.B EACCES +or +.BR EINVAL . +Make sure that userspace object managers are granted appropriate access to +netlink by the policy. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.ad l +.nh +.BR avc_init (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR security_compute_av (3), +.BR selinux (8) diff --git a/man/man3/avc_has_perm_noaudit.3 b/man/man3/avc_has_perm_noaudit.3 new file mode 100644 index 0000000..3caf27b --- /dev/null +++ b/man/man3/avc_has_perm_noaudit.3 @@ -0,0 +1 @@ +.so man3/avc_has_perm.3 diff --git a/man/man3/avc_init.3 b/man/man3/avc_init.3 new file mode 100644 index 0000000..e26c3be --- /dev/null +++ b/man/man3/avc_init.3 @@ -0,0 +1,196 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2004 +.TH "avc_init" "3" "27 May 2004" "" "SELinux API documentation" +.SH "NAME" +avc_init \- legacy userspace SELinux AVC setup +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_init(const char *" msgprefix , +.in +\w'int avc_init('u +.BI "const struct avc_memory_callback *" mem_callbacks , +.br +.BI "const struct avc_log_callback *" log_callbacks , +.br +.BI "const struct avc_thread_callback *" thread_callbacks , +.br +.BI "const struct avc_lock_callback *" lock_callbacks ");" +. +.SH "DESCRIPTION" +.BR avc_init () +is deprecated; please use +.BR avc_open (3) +in conjunction with +.BR selinux_set_callback (3) +in all new code. + +.BR avc_init () +initializes the userspace AVC and must be called before any other AVC operation can be performed. A non-NULL +.I msgprefix +will be prepended to all audit messages produced by the userspace AVC. The default is `uavc'. The remaining arguments, if non-NULL, specify callbacks to be used by the userspace AVC. +. +.SH "CALLBACKS" +The userspace AVC can be directed how to perform memory allocation, logging, thread creation, and locking via callback functions passed to +.BR avc_init (). +The purpose of this functionality is to allow the userspace AVC to be smoothly integrated into existing userspace object managers. + +Use an +.B avc_memory_callback +structure to specify alternate functions for dynamic memory allocation. + +.RS +.ta 4n 10n 24n +.nf +struct avc_memory_callback { + void *(*func_malloc)(size_t size); + void (*func_free)(void *ptr); +}; +.fi +.ta +.RE + +The two fields of the structure should be pointers to functions which behave as +.BR malloc (3) +and +.BR free (3), +which are used by default. + +Use an +.B avc_log_callback +structure to specify alternate functions for logging. + +.RS +.ta 4n 10n 24n +.nf +struct avc_log_callback { + void (*func_log)(const char *fmt, ...); + void (*func_audit)(void *auditdata, + security_class_t class, + char *msgbuf, size_t msgbufsize); +}; +.fi +.ta +.RE + +The +.B func_log +callback should accept a +.BR printf (3) +style format and arguments and log them as desired. The default behavior prints the message on the standard error. The +.B func_audit +callback should interpret the +.I auditdata +parameter for the given +.IR class , +printing a human-readable interpretation to +.I msgbuf +using no more than +.I msgbufsize +characters. The default behavior is to ignore +.IR auditdata . + +Use an +.B avc_thread_callback +structure to specify functions for starting and manipulating threads. + +.RS +.ta 4n 10n 24n +.nf +struct avc_thread_callback { + void *(*func_create_thread)(void (*run)(void)); + void (*func_stop_thread)(void *thread); +}; +.fi +.ta +.RE + +The +.B func_create_thread +callback should create a new thread and return a pointer which references it. The thread should execute the +.I run +argument, which does not return under normal conditions. The +.B func_stop_thread +callback should cancel the running thread referenced by +.IR thread . +By default, threading is not used; see +.B NETLINK NOTIFICATION +below. + +Use an +.B avc_lock_callback +structure to specify functions to create, obtain, and release locks for use by threads. + +.RS +.ta 4n 10n 24n +.nf +struct avc_lock_callback { + void *(*func_alloc_lock)(void); + void (*func_get_lock)(void *lock); + void (*func_release_lock)(void *lock); + void (*func_free_lock)(void *lock); +}; +.fi +.ta +.RE + +The +.B func_alloc_lock +callback should create a new lock, returning a pointer which references it. The +.B func_get_lock +callback should obtain +.IR lock , +blocking if necessary. The +.B func_release_lock +callback should release +.IR lock . +The +.B func_free_lock +callback should destroy +.IR lock , +freeing any resources associated with it. The default behavior is not to perform any locking. Note that undefined behavior may result if threading is used without appropriate locking. +. +.SH "NETLINK NOTIFICATION" +Beginning with version 2.6.4, the Linux kernel supports SELinux status change notification via netlink. Two message types are currently implemented, indicating changes to the enforcing mode and to the loaded policy in the kernel, respectively. The userspace AVC listens for these messages and takes the appropriate action, modifying the behavior of +.BR avc_has_perm (3) +to reflect the current enforcing mode and flushing the cache on receipt of a policy load notification. Audit messages are produced when netlink notifications are processed. + +In the default single-threaded mode, the userspace AVC checks for new netlink messages at the start of each permission query. If threading and locking callbacks are passed to +.BR avc_init () +however, a dedicated thread will be started to listen on the netlink socket. This may increase performance and will ensure that log messages are generated immediately rather than at the time of the next permission query. +. +.SH "RETURN VALUE" +Functions with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "NOTES" +The +.I msgprefix +argument to +.BR avc_init () +currently has a length limit of 15 characters and will be truncated if necessary. + +If a provided +.B func_malloc +callback does not set +.I errno +appropriately on error, userspace AVC calls may exhibit the +same behavior. + +If a netlink thread has been created and an error occurs on the socket (such as an access error), the thread may terminate and cause the userspace AVC to return +.B EINVAL +on all further permission checks until +.B avc_destroy +is called. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR avc_open (3), +.BR selinux_set_callback (3), +.BR selinux (8) diff --git a/man/man3/avc_netlink_acquire_fd.3 b/man/man3/avc_netlink_acquire_fd.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/man/man3/avc_netlink_acquire_fd.3 @@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3 diff --git a/man/man3/avc_netlink_check_nb.3 b/man/man3/avc_netlink_check_nb.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/man/man3/avc_netlink_check_nb.3 @@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3 diff --git a/man/man3/avc_netlink_close.3 b/man/man3/avc_netlink_close.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/man/man3/avc_netlink_close.3 @@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3 diff --git a/man/man3/avc_netlink_loop.3 b/man/man3/avc_netlink_loop.3 new file mode 100644 index 0000000..c8268a1 --- /dev/null +++ b/man/man3/avc_netlink_loop.3 @@ -0,0 +1,84 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: KaiGai Kohei (kaigai@ak.jp.nec.com) 2009 +.TH "avc_netlink_loop" "3" "30 Mar 2009" "" "SELinux API documentation" +.SH "NAME" +avc_netlink_open, avc_netlink_close, avc_netlink_acquire_fd, +avc_netlink_release_fd, avc_netlink_check_nb, avc_netlink_loop \- SELinux +netlink processing +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_netlink_open(int " blocking ");" +.sp +.B void avc_netlink_close(void); +.sp +.B int avc_netlink_acquire_fd(void); +.sp +.B void avc_netlink_release_fd(void); +.sp +.B void avc_netlink_loop(void); +.sp +.B int avc_netlink_check_nb(void); +. +.SH "DESCRIPTION" +These functions enable applications to handle notification of SELinux events +via netlink. The userspace AVC normally checks for netlink messages on each +call to +.BR avc_has_perm (3). +Applications may wish to override this behavior and check for notification +separately, for example in a +.BR select (2) +loop. These functions also permit netlink monitoring without requiring a +call to +.BR avc_open (3). + +.BR avc_netlink_open () +opens a netlink socket to receive SELinux notifications. The socket +descriptor is stored internally; use +.BR avc_netlink_acquire_fd (3) +to take ownership of it in application code. The +.I blocking +argument controls whether the O_NONBLOCK flag is set on the socket descriptor. +.BR avc_open (3) +calls this function internally, specifying non-blocking behavior. + +.BR avc_netlink_close () +closes the netlink socket. This function is called automatically by +.BR avc_destroy (3). + +.BR avc_netlink_acquire_fd () +returns the netlink socket descriptor number and informs the userspace AVC +not to check the socket descriptor automatically on calls to +.BR avc_has_perm (3). + +.BR avc_netlink_release_fd () +returns control of the netlink socket to the userspace AVC, re-enabling +automatic processing of notifications. + +.BR avc_netlink_check_nb () +checks the netlink socket for pending messages and processes them. +Callbacks for policyload and enforcing changes will be called; +see +.BR selinux_set_callback (3). +This function does not block. + +.BR avc_netlink_loop () +enters a loop blocking on the netlink socket and processing messages as they +are received. This function will not return unless an error occurs on +the socket, in which case the socket is closed. +. +.SH "RETURN VALUE" +.BR avc_netlink_acquire_fd () +returns a non-negative file descriptor number on success. Other functions +with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR avc_open (3), +.BR selinux_set_callback (3), +.BR selinux (8) diff --git a/man/man3/avc_netlink_open.3 b/man/man3/avc_netlink_open.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/man/man3/avc_netlink_open.3 @@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3 diff --git a/man/man3/avc_netlink_release_fd.3 b/man/man3/avc_netlink_release_fd.3 new file mode 100644 index 0000000..293a947 --- /dev/null +++ b/man/man3/avc_netlink_release_fd.3 @@ -0,0 +1 @@ +.so man3/avc_netlink_loop.3 diff --git a/man/man3/avc_open.3 b/man/man3/avc_open.3 new file mode 100644 index 0000000..5b275a8 --- /dev/null +++ b/man/man3/avc_open.3 @@ -0,0 +1,69 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2008 +.TH "avc_open" "3" "12 Jun 2008" "" "SELinux API documentation" +.SH "NAME" +avc_open, avc_destroy, avc_reset, avc_cleanup \- userspace SELinux AVC setup and teardown +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int avc_open(struct selinux_opt *" options ", unsigned " nopt ");" +.sp +.BI "void avc_destroy(void);" +.sp +.BI "int avc_reset(void);" +.sp +.BI "void avc_cleanup(void);" +. +.SH "DESCRIPTION" +.BR avc_open () +initializes the userspace AVC and must be called before any other AVC operation can be performed. + +.BR avc_destroy () +destroys the userspace AVC, freeing all internal memory structures. After this call has been made, +.BR avc_open () +must be called again before any AVC operations can be performed. + +.BR avc_reset () +flushes the userspace AVC, causing it to forget any cached access decisions. The userspace AVC normally calls this function automatically when needed, see +.B NETLINK NOTIFICATION +below. + +.BR avc_cleanup () +attempts to free unused memory within the userspace AVC, but does not flush any cached access decisions. Under normal operation, calling this function should not be necessary. +.SH "OPTIONS" +The userspace AVC obeys callbacks set via +.BR selinux_set_callback (3), +in particular the logging and audit callbacks. + +The options which may be passed to +.BR avc_open () +include the following: +.TP +.B AVC_OPT_SETENFORCE +This option forces the userspace AVC into enforcing mode if the option value is non-NULL; permissive mode otherwise. The system enforcing mode will be ignored. +. +.SH "NETLINK NOTIFICATION" +Beginning with version 2.6.4, the Linux kernel supports SELinux status change notification via netlink. Two message types are currently implemented, indicating changes to the enforcing mode and to the loaded policy in the kernel, respectively. The userspace AVC listens for these messages and takes the appropriate action, modifying the behavior of +.BR avc_has_perm (3) +to reflect the current enforcing mode and flushing the cache on receipt of a policy load notification. Audit messages are produced when netlink notifications are processed. +. +.SH "RETURN VALUE" +Functions with a return value return zero on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR selinux (8), +.BR avc_has_perm (3), +.BR avc_context_to_sid (3), +.BR avc_cache_stats (3), +.BR avc_add_callback (3), +.BR selinux_set_callback (3), +.BR security_compute_av (3) diff --git a/man/man3/avc_reset.3 b/man/man3/avc_reset.3 new file mode 100644 index 0000000..ca549ae --- /dev/null +++ b/man/man3/avc_reset.3 @@ -0,0 +1 @@ +.so man3/avc_open.3 diff --git a/man/man3/avc_sid_stats.3 b/man/man3/avc_sid_stats.3 new file mode 100644 index 0000000..6732dc1 --- /dev/null +++ b/man/man3/avc_sid_stats.3 @@ -0,0 +1 @@ +.so man3/avc_cache_stats.3 diff --git a/man/man3/avc_sid_to_context.3 b/man/man3/avc_sid_to_context.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/man/man3/avc_sid_to_context.3 @@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3 diff --git a/man/man3/checkPasswdAccess.3 b/man/man3/checkPasswdAccess.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/checkPasswdAccess.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/context_free.3 b/man/man3/context_free.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_free.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_new.3 b/man/man3/context_new.3 new file mode 100644 index 0000000..3dabac3 --- /dev/null +++ b/man/man3/context_new.3 @@ -0,0 +1,83 @@ +.TH "context_new" "3" "20 December 2011" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +context_new, context_str, context_free, context_type_get, context_type_set, context_range_get, context_range_set,context_role_get, context_role_set, context_user_get, context_user_set \- Routines to manipulate SELinux security contexts +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "context_t context_new(const char *" context_str ); +.sp +.BI "const char * context_str(context_t " con ); +.sp +.BI "void context_free(context_t " con ); +.sp +.BI "const char * context_type_get(context_t " con ); +.sp +.BI "const char * context_range_get(context_t " con ); +.sp +.BI "const char * context_role_get(context_t " con ); +.sp +.BI "const char * context_user_get(context_t " con ); +.sp +.BI "int context_type_set(context_t " con ", const char *" type ); +.sp +.BI "int context_range_set(context_t " con ", const char *" range ); +.sp +.BI "int context_role_set(context_t " con ", const char *" role ); +.sp +.BI "int context_user_set(context_t " con ", const char *" user ); +. +.SH "DESCRIPTION" +These functions allow an application to manipulate the fields of a +security context string without requiring it to know the format of the +string. + +.BR context_new () +returns a new context initialized to a context string. + +.BR context_str () +returns a pointer to the string value of the +.BR context_t , +valid until the next call to +.BR context_str () +or +.BR context_free () +for the same +.BR context_t* . + +.BR context_free () +frees the storage used by a context. + +.BR context_type_get (), +.BR context_range_get (), +.BR context_role_get (), +.BR \%context_user_get () +get a pointer to the string value of a context component. + +.B Note: +Values returned by the get functions are only valid until the next call +to a set function or +.BR context_free () +for the same +.B context_t +structure. + +.BR context_type_set (), +.BR context_range_set (), +.BR context_role_set (), +.BR \%context_user_set () +set a context component. +. +.SH "RETURN VALUE" +On failure +.BR context_*_set () +functions return non-zero and 0 on success. + +The other functions return NULL on failure and non-NULL on success. + +On failure +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/context_range_get.3 b/man/man3/context_range_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_range_get.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_range_set.3 b/man/man3/context_range_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_range_set.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_role_get.3 b/man/man3/context_role_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_role_get.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_role_set.3 b/man/man3/context_role_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_role_set.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_type_get.3 b/man/man3/context_type_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_type_get.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_type_set.3 b/man/man3/context_type_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_type_set.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_user_get.3 b/man/man3/context_user_get.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_user_get.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/context_user_set.3 b/man/man3/context_user_set.3 new file mode 100644 index 0000000..f4f03a6 --- /dev/null +++ b/man/man3/context_user_set.3 @@ -0,0 +1 @@ +.so man3/context_new.3 diff --git a/man/man3/fgetfilecon.3 b/man/man3/fgetfilecon.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/man/man3/fgetfilecon.3 @@ -0,0 +1 @@ +.so man3/getfilecon.3 diff --git a/man/man3/fgetfilecon_raw.3 b/man/man3/fgetfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/man/man3/fgetfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/getfilecon.3 diff --git a/man/man3/fini_selinuxmnt.3 b/man/man3/fini_selinuxmnt.3 new file mode 100644 index 0000000..d7805c9 --- /dev/null +++ b/man/man3/fini_selinuxmnt.3 @@ -0,0 +1 @@ +.so man3/init_selinuxmnt.3 diff --git a/man/man3/freecon.3 b/man/man3/freecon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/freecon.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/freeconary.3 b/man/man3/freeconary.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/freeconary.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/fsetfilecon.3 b/man/man3/fsetfilecon.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/man/man3/fsetfilecon.3 @@ -0,0 +1 @@ +.so man3/setfilecon.3 diff --git a/man/man3/fsetfilecon_raw.3 b/man/man3/fsetfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/man/man3/fsetfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/setfilecon.3 diff --git a/man/man3/get_default_context.3 b/man/man3/get_default_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_default_context.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/get_default_context_with_level.3 b/man/man3/get_default_context_with_level.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_default_context_with_level.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/get_default_context_with_role.3 b/man/man3/get_default_context_with_role.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_default_context_with_role.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/get_default_context_with_rolelevel.3 b/man/man3/get_default_context_with_rolelevel.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_default_context_with_rolelevel.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/get_default_type.3 b/man/man3/get_default_type.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_default_type.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/get_ordered_context_list.3 b/man/man3/get_ordered_context_list.3 new file mode 100644 index 0000000..e084da4 --- /dev/null +++ b/man/man3/get_ordered_context_list.3 @@ -0,0 +1,108 @@ +.TH "get_ordered_context_list" "3" "1 January 2004" "russell@coker.com.au" "SELinux" +.SH "NAME" +get_ordered_context_list, get_ordered_context_list_with_level, get_default_context, get_default_context_with_level, get_default_context_with_role, get_default_context_with_rolelevel, query_user_context, manual_user_enter_context, get_default_role \- determine SELinux context(s) for user sessions +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int get_ordered_context_list(const char *" user ", char *" fromcon ", char ***" list ); +.sp +.BI "int get_ordered_context_list_with_level(const char *" user ", const char *" level ", char *" fromcon ", char ***" list ); +.sp +.BI "int get_default_context(const char *" user ", char *" fromcon ", char **" newcon ); +.sp +.BI "int get_default_context_with_level(const char *" user ", const char *" level ", char *" fromcon ", char **" newcon ); +.sp +.BI "int get_default_context_with_role(const char *" user ", const char *" role ", char *" fromcon ", char **" newcon "); +.sp +.BI "int get_default_context_with_rolelevel(const char *" user ", const char *" role ", const char *" level ", char *" fromcon ", char **" newcon "); +.sp +.BI "int query_user_context(char **" list ", char **" newcon ); +.sp +.BI "int manual_user_enter_context(const char *" user ", char **" newcon ); +.sp +.BI "int get_default_type(const char *" role ", char **" type ); +. +.SH "DESCRIPTION" +.BR get_ordered_context_list () +invokes the +.BR security_compute_user (3) +function to obtain the list of contexts for the specified +.I user +that are reachable from the specified +.I fromcon +context. The function then orders the resulting list based on the global +.I \%/etc/selinux/{SELINUXTYPE}/contexts/default_contexts +file and the per-user +.I \%/etc/selinux/{SELINUXTYPE}/contexts/users/ +file if it exists. The +.I fromcon +parameter may be NULL to indicate that the current context should +be used. The function returns the number of contexts in the +list, or \-1 upon errors. The list must be freed using the +.BR freeconary (3) +function. + +.BR get_ordered_context_list_with_level () +invokes the +.BR \%get_ordered_context_list () +function and applies the specified level. + +.BR get_default_context () +is the same as +.BR get_ordered_context_list () +but only returns a single context +which has to be freed with +.BR freecon (3). + +.BR get_default_context_with_level () +invokes the +.BR get_default_context () +function and applies the specified level. + +.BR get_default_context_with_role () +is the same as +.BR get_default_context () +but only returns a context with the specified role, returning \-1 if no +such context is reachable for the user. + +.BR get_default_context_with_rolelevel () +invokes the +.BR \%get_default_context_with_role () +function and applies the specified level. + +.BR query_user_context () +takes a list of contexts, queries the user via stdin/stdout as to which context +they want, and returns a new context as selected by the user (which has to be +freed with +.BR freecon (3)). + +.BR manual_user_enter_context () +allows the user to manually enter a context as a fallback if a list of +authorized contexts could not be obtained. Caller must free via +.BR freecon (3). + +.BR get_default_type () +Get the default type (domain) for +.I role +and set +.I type +to refer to it, which has to be freed with free. +. +.SH "RETURN VALUE" +.BR get_ordered_context_list () +and +.BR get_ordered_context_list_with_level () +return the number of contexts in the list upon success or \-1 upon errors. +The other functions return 0 for success or \-1 for errors. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux (8), +.BR freeconary (3), +.BR freecon (3), +.BR security_compute_av (3), +.BR getseuserbyname (3) diff --git a/man/man3/get_ordered_context_list_with_level.3 b/man/man3/get_ordered_context_list_with_level.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/get_ordered_context_list_with_level.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/getcon.3 b/man/man3/getcon.3 new file mode 100644 index 0000000..67872a4 --- /dev/null +++ b/man/man3/getcon.3 @@ -0,0 +1,126 @@ +.TH "getcon" "3" "21 December 2011" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getcon, getprevcon, getpidcon \- get SELinux security context of a process + +freecon, freeconary \- free memory associated with SELinux security contexts + +getpeercon \- get security context of a peer socket + +setcon \- set current security context of a process +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getcon(char **" context ); +.sp +.BI "int getcon_raw(char **" context ); +.sp +.BI "int getprevcon(char **" context ); +.sp +.BI "int getprevcon_raw(char **" context ); +.sp +.BI "int getpidcon(pid_t " pid ", char **" context ); +.sp +.BI "int getpidcon_raw(pid_t " pid ", char **" context ); +.sp +.BI "int getpeercon(int " fd ", char **" context ); +.sp +.BI "int getpeercon_raw(int " fd ", char **" context ); +.sp +.BI "void freecon(char *" con ); +.sp +.BI "void freeconary(char **" con ); +.sp +.BI "int setcon(char *" context ); +.sp +.BI "int setcon_raw(char *" context ); +. +.SH "DESCRIPTION" +.BR getcon () +retrieves the context of the current process, which must be free'd with +freecon. + +.BR getprevcon () +same as getcon but gets the context before the last exec. + +.BR getpidcon () +returns the process context for the specified PID. + +.BR getpeercon () +retrieves context of peer socket, and set +.BI * context +to refer to it, which must be free'd with +.BR freecon (). + +.BR freecon () +frees the memory allocated for a security context. + +.BR freeconary () +frees the memory allocated for a context array. + +If +.I con +is NULL, no operation is performed. + +.BR setcon () +sets the current security context of the process to a new value. Note +that use of this function requires that the entire application be +trusted to maintain any desired separation between the old and new +security contexts, unlike exec-based transitions performed via +.BR setexeccon (3). +When possible, decompose your application and use +.BR setexeccon (3) +and +.BR execve (3) +instead. + +Since access to file descriptors is revalidated upon use by SELinux, +the new context must be explicitly authorized in the policy to use the +descriptors opened by the old context if that is desired. Otherwise, +attempts by the process to use any existing descriptors (including +.IR stdin , +.IR stdout , +and +.IR stderr ) +after performing the +.BR setcon () +will fail. + +A multi-threaded application can perform a +.BR setcon () +prior to creating +any child threads, in which case all of the child threads will inherit +the new context. However, prior to Linux 2.6.28, +.BR setcon () +would fail if there are any other +threads running in the same process since this would yield +an inconsistency among the security contexts of threads sharing +the same memory space. Since Linux 2.6.28, +.BR setcon() +is permitted for threads within a multi-threaded process if the +new security context is bounded by the old security context, where +the bounded relation is defined through typebounds statements in the +policy and guarantees that the new security context has a subset of +the permissions of the old security context. + +If the process was being ptraced at the time of the +.BR setcon () +operation, ptrace permission will be revalidated against the new +context and the +.BR setcon () +will fail if it is not allowed by policy. + +.BR getcon_raw (), +.BR getprevcon_raw (), +.BR getpidcon_raw (), +.BR getpeercon_raw () +and +.BR setcon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. +. +.SH "RETURN VALUE" +On error \-1 is returned. On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " setexeccon "(3)" diff --git a/man/man3/getcon_raw.3 b/man/man3/getcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getcon_raw.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getexeccon.3 b/man/man3/getexeccon.3 new file mode 100644 index 0000000..d6222a4 --- /dev/null +++ b/man/man3/getexeccon.3 @@ -0,0 +1,105 @@ +.TH "getexeccon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getexeccon, setexeccon \- get or set the SELinux security context used for executing a new process + +rpm_execcon \- run a helper for rpm in an appropriate security context +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getexeccon(char **" context ); +.sp +.BI "int getexeccon_raw(char **" context ); +.sp +.BI "int setexeccon(char *" context ); +.sp +.BI "int setexeccon_raw(char *" context ); +.sp +.BI "int setexecfilecon(const char *" filename ", const char *" fallback_type ); +.sp +.BI "int rpm_execcon(unsigned int " verified ", const char *" filename ", char *const " argv "[] , char *const " envp "[]); +. +.SH "DESCRIPTION" +.BR getexeccon () +retrieves the context used for executing a new process. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getexeccon () +sets +.BI * context +to NULL if no exec context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setexeccon () +sets the context used for the next +.BR execve (2) +call. +NULL can be passed to +.BR setexeccon () +to reset to the default policy behavior. +The exec context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setexeccon () +can be applied prior to library +functions that internally perform an +.BR execve (2), +e.g. +.BR execl *(3), +.BR execv *(3), +.BR popen (3), +in order to set an exec context for that operation. + +.BR getexeccon_raw () +and +.BR setexeccon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform an +.BR execve (2) +must take care to +save, reset, and restore the exec context to avoid unexpected behavior. + +.BR setexecfilecon () +sets the context used for the next +.BR execve (2) +call, based on the policy for the +.IR filename , +and falling back to a new context with a +.I fallback_type +in case there is no transition. + +.BR rpm_execcon () +is deprecated; please use +.BR setexecfilecon () +in conjunction with +.BR execve (2) +in all new code. This function +runs a helper for rpm in an appropriate security context. The +verified parameter should contain the return code from the signature +verification (0 == ok, 1 == notfound, 2 == verifyfail, 3 == +nottrusted, 4 == nokey), although this information is not yet used by +the function. The function determines the proper security context for +the helper based on policy, sets the exec context accordingly, and +then executes the specified filename with the provided argument and +environment arrays. +. +.SH "RETURN VALUE" +On error \-1 is returned. + +On success +.BR getexeccon (), +.BR setexeccon () +and +.BR setexecfilecon () +return 0. +.BR rpm_execcon () +only returns upon errors, as it calls +.BR execve (2). +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3)" diff --git a/man/man3/getexeccon_raw.3 b/man/man3/getexeccon_raw.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/man/man3/getexeccon_raw.3 @@ -0,0 +1 @@ +.so man3/getexeccon.3 diff --git a/man/man3/getfilecon.3 b/man/man3/getfilecon.3 new file mode 100644 index 0000000..5bb575b --- /dev/null +++ b/man/man3/getfilecon.3 @@ -0,0 +1,72 @@ +.TH "getfilecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getfilecon, fgetfilecon, lgetfilecon \- get SELinux security context of a file +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getfilecon(const char *" path ", char **" con ); +.sp +.BI "int getfilecon_raw(const char *" path ", char **" con ); +.sp +.BI "int lgetfilecon(const char *" path ", char **" con ); +.sp +.BI "int lgetfilecon_raw(const char *" path ", char **" con ); +.sp +.BI "int fgetfilecon(int "fd ", char **" con ); +.sp +.BI "int fgetfilecon_raw(int "fd ", char **" con ); +. +.SH "DESCRIPTION" +.BR getfilecon () +retrieves the context associated with the given path in the file system, the +length of the context is returned. + +.BR lgetfilecon () +is identical to +.BR getfilecon (), +except in the case of a symbolic link, where the +link itself is interrogated, not the file that it refers to. + +.BR fgetfilecon () +is identical to +.BR getfilecon (), +only the open file pointed to by filedes (as returned by +.BR open (2)) +is interrogated in place of path. + +.BR getfilecon_raw (), +.BR lgetfilecon_raw () +and +.BR fgetfilecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +The returned context should be freed with +.BR freecon (3) +if non-NULL. +. +.SH "RETURN VALUE" +On success, a positive number is returned indicating the size of the +extended attribute value. On failure, \-1 is returned and +.I errno +is set appropriately. + +If the context does not exist, or the process has no access to +this attribute, +.I errno +is set to +.BR ENODATA . + +If extended attributes are not supported by the filesystem, or are +disabled, +.I errno +is set to +.BR ENOTSUP . + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/getfilecon_raw.3 b/man/man3/getfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/man/man3/getfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/getfilecon.3 diff --git a/man/man3/getfscreatecon.3 b/man/man3/getfscreatecon.3 new file mode 100644 index 0000000..c6faadc --- /dev/null +++ b/man/man3/getfscreatecon.3 @@ -0,0 +1,62 @@ +.TH "getfscreatecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +getfscreatecon, setfscreatecon \- get or set the SELinux security context used for creating a new file system object +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getfscreatecon(char **" con ); +.sp +.BI "int getfscreatecon_raw(char **" con ); +.sp +.BI "int setfscreatecon(char *" context ); +.sp +.BI "int setfscreatecon_raw(char *" context ); +. +.SH "DESCRIPTION" +.BR getfscreatecon () +retrieves the context used for creating a new file system object. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getfscreatecon () +sets *con to NULL if no fscreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setfscreatecon () +sets the context used for creating a new file system object. +NULL can be passed to +.BR setfscreatecon () +to reset to the default policy behavior. +The fscreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setfscreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getfscreatecon_raw () +and +.BR setfscreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setfscreatecon () +must take care to +save, reset, and restore the fscreate context to avoid unexpected behavior. +. + +.br +.B Note: +Contexts are thread specific. + +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3), " getexeccon "(3)" diff --git a/man/man3/getfscreatecon_raw.3 b/man/man3/getfscreatecon_raw.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/man/man3/getfscreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getfscreatecon.3 diff --git a/man/man3/getkeycreatecon.3 b/man/man3/getkeycreatecon.3 new file mode 100644 index 0000000..7887b9b --- /dev/null +++ b/man/man3/getkeycreatecon.3 @@ -0,0 +1,61 @@ +.TH "getkeycreatecon" "3" "9 September 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getkeycreatecon, setkeycreatecon \- get or set the SELinux security context used for creating a new kernel keyrings +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getkeycreatecon(char **" con ); +.sp +.BI "int getkeycreatecon_raw(char **" con ); +.sp +.BI "int setkeycreatecon(char *" context ); +.sp +.BI "int setkeycreatecon_raw(char *" context ); +. +.SH "DESCRIPTION" +.BR getkeycreatecon () +retrieves the context used for creating a new kernel keyring. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getkeycreatecon () +sets *con to NULL if no keycreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setkeycreatecon () +sets the context used for creating a new kernel keyring. +NULL can be passed to +.BR setkeycreatecon () +to reset to the default policy behavior. +The keycreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setkeycreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getkeycreatecon_raw () +and +.BR setkeycreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setkeycreatecon () +must take care to +save, reset, and restore the keycreate context to avoid unexpected behavior. + +.br +.B Note: +Contexts are thread specific. +. +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3), " getexeccon "(3)" diff --git a/man/man3/getkeycreatecon_raw.3 b/man/man3/getkeycreatecon_raw.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/man/man3/getkeycreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getkeycreatecon.3 diff --git a/man/man3/getpeercon.3 b/man/man3/getpeercon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getpeercon.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getpeercon_raw.3 b/man/man3/getpeercon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getpeercon_raw.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getpidcon.3 b/man/man3/getpidcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getpidcon.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getpidcon_raw.3 b/man/man3/getpidcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getpidcon_raw.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getprevcon.3 b/man/man3/getprevcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getprevcon.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getprevcon_raw.3 b/man/man3/getprevcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/getprevcon_raw.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/getseuserbyname.3 b/man/man3/getseuserbyname.3 new file mode 100644 index 0000000..c231e65 --- /dev/null +++ b/man/man3/getseuserbyname.3 @@ -0,0 +1,33 @@ +.TH "getseuserbyname" "3" "29 September 2005" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getseuserbyname \- get SELinux username and level for a given Linux username +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getseuserbyname(const char *" linuxuser ", char **" selinuxuser ", char **" level "); +. +.SH "DESCRIPTION" +.BR getseuserbyname () +retrieves the SELinux username and security level associated with +a given Linux username. The SELinux username and security level can +then be passed to other libselinux functions such as +.BR \%get_ordered_context_list_with_level (3) +and +.BR \%get_default_context_with_level (3). + +The returned SELinux username and level should be freed by the caller +using free. +. +.SH "RETURN VALUE" +On success, 0 is returned. +On failure, \-1 is returned and +.I errno +is set appropriately. + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/getsockcreatecon.3 b/man/man3/getsockcreatecon.3 new file mode 100644 index 0000000..9223f60 --- /dev/null +++ b/man/man3/getsockcreatecon.3 @@ -0,0 +1,62 @@ +.TH "getsockcreatecon" "3" "24 September 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +getsockcreatecon, setsockcreatecon \- get or set the SELinux security context used for creating a new labeled sockets +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int getsockcreatecon(char **" con ); +.sp +.BI "int getsockcreatecon_raw(char **" con ); +.sp +.BI "int setsockcreatecon(char *" context ); +.sp +.BI "int setsockcreatecon_raw(char *" context ); +. +.SH "DESCRIPTION" +.BR getsockcreatecon () +retrieves the context used for creating a new labeled network socket. +This returned context should be freed with +.BR freecon (3) +if non-NULL. +.BR getsockcreatecon () +sets *con to NULL if no sockcreate context has been explicitly +set by the program (i.e. using the default policy behavior). + +.BR setsockcreatecon () +sets the context used for creating a new labeled network sockets +NULL can be passed to +.BR setsockcreatecon () +to reset to the default policy behavior. +The sockcreate context is automatically reset after the next +.BR execve (2), +so a program doesn't need to explicitly sanitize it upon startup. + +.BR setsockcreatecon () +can be applied prior to library +functions that internally perform an file creation, +in order to set an file context on the objects. + +.BR getsockcreatecon_raw () +and +.BR setsockcreatecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.B Note: +Signal handlers that perform a +.BR setsockcreatecon () +must take care to +save, reset, and restore the sockcreate context to avoid unexpected behavior. +. + +.br +.B Note: +Contexts are thread specific. + +.SH "RETURN VALUE" +On error \-1 is returned. +On success 0 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3), " getcon "(3) diff --git a/man/man3/getsockcreatecon_raw.3 b/man/man3/getsockcreatecon_raw.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/man/man3/getsockcreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getsockcreatecon.3 diff --git a/man/man3/init_selinuxmnt.3 b/man/man3/init_selinuxmnt.3 new file mode 100644 index 0000000..8466f9f --- /dev/null +++ b/man/man3/init_selinuxmnt.3 @@ -0,0 +1,31 @@ +.TH "init_selinuxmnt" "3" "21 Nov 2009" "" "SELinux API documentation" +.SH "NAME" +init_selinuxmnt \- initialize the global variable selinux_mnt +. +.SH "SYNOPSIS" +.BI "static void init_selinuxmnt(void);" +.sp +.BI "static void fini_selinuxmnt(void);" +.sp +.BI "void set_selinuxmnt(char *" mnt ");" +. +.SH "DESCRIPTION" +.BR init_selinuxmnt () +initializes the global variable +.I selinux_mnt +to the selinuxfs mountpoint. + +.BR fini_selinuxmnt () +deinitializes the global variable +.I selinux_mnt +that stores the selinuxfs mountpoint. + +.BR set_selinuxmnt () +changes the selinuxfs mountpoint to +.IR mnt . +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia +. +.SH "SEE ALSO" +.BR selinux (8), diff --git a/man/man3/is_context_customizable.3 b/man/man3/is_context_customizable.3 new file mode 100644 index 0000000..c858a02 --- /dev/null +++ b/man/man3/is_context_customizable.3 @@ -0,0 +1,24 @@ +.TH "is_context_customizable" "3" "10 January 2005" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +is_context_customizable \- check whether SELinux context type is customizable by the administrator +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int is_context_customizable(char *" scon ); +. +.SH "DESCRIPTION" +This function checks whether the type of scon is in the +.I /etc/selinux/{SELINUXTYPE}/context/customizable_types +file. A customizable type is a file context type that +administrators set on files, usually to allow certain domains to share the file content. restorecon and setfiles, by default, leave these context in place. +. +.SH "RETURN VALUE" +Returns 1 if security context is customizable or 0 if it is not. +Returns \-1 on error. +. +.SH "FILE" +.I /etc/selinux/{SELINUXTYPE}/context/customizable_types +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/is_selinux_enabled.3 b/man/man3/is_selinux_enabled.3 new file mode 100644 index 0000000..df62c22 --- /dev/null +++ b/man/man3/is_selinux_enabled.3 @@ -0,0 +1,26 @@ +.TH "is_selinux_enabled" "3" "7 Mar 2010" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +is_selinux_enabled \- check whether SELinux is enabled +. +.SH "NAME" +is_selinux_mls_enabled \- check whether SELinux is enabled for (Multi Level Security) MLS +. +.SH "SYNOPSIS" +.B #include +.sp +.B int is_selinux_enabled(); +.sp +.B int is_selinux_mls_enabled(); +. +.SH "DESCRIPTION" +.BR is_selinux_enabled () +returns 1 if SELinux is running or 0 if it is not. +On error, \-1 is returned. + +.BR is_selinux_mls_enabled () +returns 1 if SELinux is capable of running in MLS mode or 0 if it is not. To +determine the policy in use on the system, use +.BR selinux_getpolicytype (3). +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/is_selinux_mls_enabled.3 b/man/man3/is_selinux_mls_enabled.3 new file mode 100644 index 0000000..2817639 --- /dev/null +++ b/man/man3/is_selinux_mls_enabled.3 @@ -0,0 +1 @@ +.so man3/is_selinux_enabled.3 diff --git a/man/man3/lgetfilecon.3 b/man/man3/lgetfilecon.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/man/man3/lgetfilecon.3 @@ -0,0 +1 @@ +.so man3/getfilecon.3 diff --git a/man/man3/lgetfilecon_raw.3 b/man/man3/lgetfilecon_raw.3 new file mode 100644 index 0000000..ae6dfcf --- /dev/null +++ b/man/man3/lgetfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/getfilecon.3 diff --git a/man/man3/lsetfilecon.3 b/man/man3/lsetfilecon.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/man/man3/lsetfilecon.3 @@ -0,0 +1 @@ +.so man3/setfilecon.3 diff --git a/man/man3/lsetfilecon_raw.3 b/man/man3/lsetfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/man/man3/lsetfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/setfilecon.3 diff --git a/man/man3/manual_user_enter_context.3 b/man/man3/manual_user_enter_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/manual_user_enter_context.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/matchmediacon.3 b/man/man3/matchmediacon.3 new file mode 100644 index 0000000..187e1c1 --- /dev/null +++ b/man/man3/matchmediacon.3 @@ -0,0 +1,30 @@ +.TH "matchmediacon" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +matchmediacon \- get the default SELinux security context for the specified mediatype from the policy +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int matchmediacon(const char *" media ", char **" con ); +. +.SH "DESCRIPTION" +.BR matchmediacon () +matches the specified media type with the media contexts configuration and +sets the security context +.I con +to refer to the resulting context. +.sp +.B Note: +Caller must free returned security context +.I con +using +.BR freecon (3). +. +.SH "RETURN VALUE" +Returns 0 on success or \-1 otherwise. +. +.SH Files +.I /etc/selinux/{POLICYTYPE}/contexts/files/media +. +.SH "SEE ALSO" +.BR selinux "(8), " freecon "(3) diff --git a/man/man3/matchpathcon.3 b/man/man3/matchpathcon.3 new file mode 100644 index 0000000..177f15d --- /dev/null +++ b/man/man3/matchpathcon.3 @@ -0,0 +1,127 @@ +.TH "matchpathcon" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +matchpathcon, matchpathcon_index \- get the default SELinux security context for the specified path from the file contexts configuration +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int matchpathcon_init(const char *" path ");" +.sp +.BI "int matchpathcon_init_prefix(const char *" path ", const char *" prefix ");" +.sp +.BI "int matchpathcon_fini(void);" +.sp +.BI "int matchpathcon(const char *" path ", mode_t " mode ", char **" con "); +.sp +.BI "int matchpathcon_index(const char *" name ", mode_t " mode ", char **" con ");" +. +.SH "DESCRIPTION" + +This family of functions is deprecated. For new code, please use +.BR selabel_open (3) +with the +.B SELABEL_CTX_FILE +backend in place of +.BR matchpathcon_init (), +use +.BR selabel_close (3) +in place of +.BR matchpathcon_fini (), +and use +.BR selabel_lookup (3) +in place of +.BR matchpathcon (). + +The remaining description below is for the legacy interface. + +.BR matchpathcon_init () +loads the file contexts configuration specified by +.I path +into memory for use by subsequent +.BR matchpathcon () +calls. If +.I path +is NULL, then the active file contexts configuration is loaded by default, +i.e. the path returned by +.BR selinux_file_context_path (3). +Unless the +.B MATCHPATHCON_BASEONLY +flag has been set via +.BR \%set_matchpathcon_flags (3), +files with the same path prefix but a +.B \%.homedirs +and +.B .local +suffix are also looked up and loaded if present. These files provide +dynamically generated entries for user home directories and for local +customizations. + +.BR matchpathcon_init_prefix () +is the same as +.BR matchpathcon_init () +but only loads entries with regular expressions whose first pathname +component is a prefix of +.I \%prefix +, e.g. pass "/dev" if you only intend to call +.BR matchpathcon () +with pathnames beginning with /dev. +However, this optimization is no longer necessary due to the use of +.I file_contexts.bin +files with precompiled regular expressions, so use of this interface +is deprecated. + +.BR matchpathcon_fini () +frees the memory allocated by a prior call to +.BR matchpathcon_init. () +This function can be used to free and reset the internal state between multiple +.BR matchpathcon_init () +calls, or to free memory when finished using +.BR matchpathcon (). + +.BR matchpathcon () +matches the specified +.I pathname, +after transformation via +.BR realpath (3) +excepting any final symbolic link component if S_IFLNK was +specified as the +.I mode, +and +.I mode +against the +.I file contexts +configuration and sets the security context +.I con +to refer to the +resulting context. The caller must free the returned security context +.I con +using +.BR freecon (3) +when finished using it. +.I mode +can be 0 to disable mode matching, but +should be provided whenever possible, as it may affect the matching. +Only the file format bits (i.e. the file type) of the +.I mode +are used. +If +.BR matchpathcon_init () +has not already been called, then this function will call it upon +its first invocation with a NULL +.I path, +defaulting to the active file contexts configuration. + +.BR matchpathcon_index () +is the same as +.BR matchpathcon () +but returns a specification index that can later be used in a +.BR matchpathcon_filespec_add (3) +call. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " set_matchpathcon_flags "(3), " set_matchpathcon_invalidcon "(3), " set_matchpathcon_printf "(3), " matchpathcon_filespec_add "(3), " matchpathcon_checkmatches "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/matchpathcon_checkmatches.3 b/man/man3/matchpathcon_checkmatches.3 new file mode 100644 index 0000000..6bbee44 --- /dev/null +++ b/man/man3/matchpathcon_checkmatches.3 @@ -0,0 +1,48 @@ +.TH "matchpathcon_checkmatches" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +matchpathcon_checkmatches, matchpathcon_filespec_add, matchpathcon_filespec_destroy, matchpathcon_filespec_eval \- check and report whether any specification index has no matches with any inode. Maintenance and statistics on inode associations +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "void matchpathcon_checkmatches(char *" str ");" +.sp +.BI "int matchpathcon_filespec_add(ino_t " ino ", int " specind ", const char *" file ");" +.sp +.BI "void matchpathcon_filespec_destroy(void);" +.sp +.BI "void matchpathcon_filespec_eval(void);" +. +.SH "DESCRIPTION" +.BR matchpathcon_checkmatches () +checks whether any specification has no matches and reports them. +The +.I str +argument is used as a prefix for any warning messages. +.sp +.BR matchpathcon_filespec_add () +maintains an association between an inode +.I ino +and a specification index +.IR specind , +and checks whether a conflicting specification is already associated +with the same inode (e.g. due to multiple hard links). If so, then +it uses the latter of the two specifications based on their order in the +.I file +context configuration. Returns the specification index used or \-1 on +error. +.sp +.BR matchpathcon_filespec_destroy () +destroys any inode associations that have been added, e.g. to restart +for a new filesystem. +.sp +.BR matchpathcon_filespec_eval () +displays statistics on the hash table usage for the inode associations. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " matchpathcon "(3), " matchpathcon_index "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/matchpathcon_filespec_add.3 b/man/man3/matchpathcon_filespec_add.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/man/man3/matchpathcon_filespec_add.3 @@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3 diff --git a/man/man3/matchpathcon_filespec_destroy.3 b/man/man3/matchpathcon_filespec_destroy.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/man/man3/matchpathcon_filespec_destroy.3 @@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3 diff --git a/man/man3/matchpathcon_filespec_eval.3 b/man/man3/matchpathcon_filespec_eval.3 new file mode 100644 index 0000000..bcbd0a6 --- /dev/null +++ b/man/man3/matchpathcon_filespec_eval.3 @@ -0,0 +1 @@ +.so man3/matchpathcon_checkmatches.3 diff --git a/man/man3/matchpathcon_fini.3 b/man/man3/matchpathcon_fini.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/man/man3/matchpathcon_fini.3 @@ -0,0 +1 @@ +.so man3/matchpathcon.3 diff --git a/man/man3/matchpathcon_index.3 b/man/man3/matchpathcon_index.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/man/man3/matchpathcon_index.3 @@ -0,0 +1 @@ +.so man3/matchpathcon.3 diff --git a/man/man3/matchpathcon_init.3 b/man/man3/matchpathcon_init.3 new file mode 100644 index 0000000..cd5df2e --- /dev/null +++ b/man/man3/matchpathcon_init.3 @@ -0,0 +1 @@ +.so man3/matchpathcon.3 diff --git a/man/man3/mode_to_security_class.3 b/man/man3/mode_to_security_class.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/mode_to_security_class.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man3/print_access_vector.3 b/man/man3/print_access_vector.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/print_access_vector.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man3/query_user_context.3 b/man/man3/query_user_context.3 new file mode 100644 index 0000000..3fbfe0e --- /dev/null +++ b/man/man3/query_user_context.3 @@ -0,0 +1 @@ +.so man3/get_ordered_context_list.3 diff --git a/man/man3/rpm_execcon.3 b/man/man3/rpm_execcon.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/man/man3/rpm_execcon.3 @@ -0,0 +1 @@ +.so man3/getexeccon.3 diff --git a/man/man3/security_av_perm_to_string.3 b/man/man3/security_av_perm_to_string.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/security_av_perm_to_string.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man3/security_av_string.3 b/man/man3/security_av_string.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/security_av_string.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man3/security_check_context.3 b/man/man3/security_check_context.3 new file mode 100644 index 0000000..2b9a2d4 --- /dev/null +++ b/man/man3/security_check_context.3 @@ -0,0 +1,23 @@ +.TH "security_check_context" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_check_context \- check the validity of a SELinux context +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int security_check_context(char *" con ); +.sp +.BI "int security_check_context_raw(char *" con ); +. +.SH "DESCRIPTION" +.BR security_check_context () +returns 0 if SELinux is running and the context is valid, otherwise it +returns \-1. + +.BR security_check_context_raw () +behaves identically to +.BR \%security_check_context () +but does not perform context translation. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/security_check_context_raw.3 b/man/man3/security_check_context_raw.3 new file mode 100644 index 0000000..ee93986 --- /dev/null +++ b/man/man3/security_check_context_raw.3 @@ -0,0 +1 @@ +.so man3/security_check_context.3 diff --git a/man/man3/security_class_to_string.3 b/man/man3/security_class_to_string.3 new file mode 100644 index 0000000..1b1b88d --- /dev/null +++ b/man/man3/security_class_to_string.3 @@ -0,0 +1,96 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "security_class_to_string" "3" "30 Mar 2007" "" "SELinux API documentation" +.SH "NAME" +security_class_to_string, security_av_perm_to_string, string_to_security_class, string_to_av_perm, security_av_string, mode_to_security_class \- convert +between SELinux class and permission values and string names. +. +print_access_vector \- display an access vector in human-readable form. +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "const char *security_class_to_string(security_class_t " tclass ");" +.sp +.BI "const char *security_av_perm_to_string(security_class_t " tclass ", access_vector_t " av ");" +.sp +.BI "int security_av_string(security_class_t " tclass ", access_vector_t " av ", char **" result ");" +.sp +.BI "security_class_t string_to_security_class(const char *" name ");" +.sp +.BI "security_class_t mode_to_security_class(mode_t " mode ");" +.sp +.BI "access_vector_t string_to_av_perm(security_class_t " tclass ", const char *" name ");" +.sp +.BI "void print_access_vector(security_class_t " tclass ", access_vector_t " av ");" +. +.SH "DESCRIPTION" +.BR security_class_to_string () +returns a string name for class +.IR tclass , +or NULL if the class is invalid. The returned string must not be modified or freed. + +.BR security_av_perm_to_string () +returns a string name for the access vector bit +.I av +of class +.IR tclass , +or NULL if either argument is invalid. The returned string must not be modified or freed. + +.BR security_av_string () +computes a full access vector string representation using +.I tclass +and +.IR av , +which may have multiple bits set. The string is returned in the memory pointed to by +.IR result , +and should be freed by the caller using +.BR free (3). + +.BR string_to_security_class () +returns the class value corresponding to the string name +.IR name , +or zero if no such class exists. + +.BR mode_to_security_class () +returns the class value corresponding to the specified +.IR mode , +or zero if no such class exists. + +.BR string_to_av_perm () +returns the access vector bit corresponding to the string name +.I name +and security class +.IR tclass , +or zero if no such value exists. + +.BR print_access_vector () +displays an access vector in human-readable form on the standard output +stream. +. +.SH "RETURN VALUE" +.BR security_av_string () +returns zero on success or \-1 on error with +.I errno +set appropriately. +.BR print_access_vector () +does not return a value. All other functions return zero or NULL on error. +. +.SH "ERRORS" +.TP +.B EINVAL +A class or access vector argument is not recognized by the currently loaded policy. + +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getcon (3), +.BR getfilecon (3) +.BR stat (3) diff --git a/man/man3/security_commit_booleans.3 b/man/man3/security_commit_booleans.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/man/man3/security_commit_booleans.3 @@ -0,0 +1 @@ +.so man3/security_load_booleans.3 diff --git a/man/man3/security_compute_av.3 b/man/man3/security_compute_av.3 new file mode 100644 index 0000000..2aade5f --- /dev/null +++ b/man/man3/security_compute_av.3 @@ -0,0 +1,138 @@ +.TH "security_compute_av" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_compute_av, security_compute_av_flags, security_compute_create, security_compute_create_name, security_compute_relabel, +security_compute_member, security_compute_user, security_get_initial_context \- query +the SELinux policy database in the kernel +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int security_compute_av(char *" scon ", char *" tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_flags(char *" scon ", char *" tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_av_flags_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", access_vector_t "requested ", struct av_decision *" avd ); +.sp +.BI "int security_compute_create(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_create_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_create_name(char *" scon ", char *" tcon ", security_class_t "tclass ", const char *" objname ", char **" newcon ); +.sp +.BI "int security_compute_create_name_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", const char *" objname ", char **" newcon ); +.sp +.BI "int security_compute_relabel(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_relabel_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_member(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_member_raw(char *" scon ", char *" tcon ", security_class_t "tclass ", char **" newcon ); +.sp +.BI "int security_compute_user(char *" scon ", const char *" username ", char ***" con ); +.sp +.BI "int security_compute_user_raw(char *" scon ", const char *" username ", char ***" con ); +.sp +.BI "int security_get_initial_context(const char *" name ", char **" con ); +.sp +.BI "int security_get_initial_context_raw(const char *" name ", char **" con ); +.sp +.BI "int selinux_check_access(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata); +.sp +.BI "int selinux_check_passwd_access(access_vector_t " requested ); +.sp +.BI "int checkPasswdAccess(access_vector_t " requested ); +. +.SH "DESCRIPTION" +.BR security_compute_av () +queries whether the policy permits the source context +.I scon +to access the target context +.I tcon +via class +.I tclass +with the +.I requested +access vector. The decision is returned in +.IR avd . + +.BR security_compute_av_flags () +is identical to +.B security_compute_av +but additionally sets the +.I flags +field of +.IR avd . +Currently one flag is supported: +.BR SELINUX_AVD_FLAGS_PERMISSIVE , +which indicates the decision is computed on a permissive domain. + +.BR security_compute_create () +is used to compute a context to use for labeling a new object in a particular +class based on a SID pair. + +.BR security_compute_create_name () +is identical to +.BR \%security_compute_create () +but also takes name of the new object in creation as an argument. +When +.B TYPE_TRANSITION +rule on the given class and a SID pair has object name extension, +we shall be able to obtain a correct +.I newcon +according to the security policy. Note that this interface is only +supported on the linux 2.6.40 or later. +In the older kernel, the object name will be simply ignored. + +.BR security_compute_relabel () +is used to compute the new context to use when relabeling an object, it is used +in the pam_selinux.so source and the newrole source to determine the correct +label for the tty at login time, but can be used for other things. + +.BR security_compute_member () +is used to compute the context to use when labeling a polyinstantiated object +instance. + +.BR security_compute_user () +is used to determine the set of user contexts that can be reached from a +source context. It is mainly used by +.BR get_ordered_context_list (). + +.BR security_get_initial_context () +is used to get the context of a kernel initial security identifier specified by +.I name + +.BR security_compute_av_raw (), +.BR security_compute_av_flags_raw (), +.BR \%security_compute_create_raw (), +.BR \%security_compute_create_name_raw (), +.BR \%security_compute_relabel_raw (), +.BR \%security_compute_member_raw (), +.BR \%security_compute_user_raw () +and +.BR \%security_get_initial_context_raw () +behave identically to their non-raw counterparts but do not perform context +translation. + +.BR selinux_check_access () +is used to check if the source context has the access permission for the specified class on the target context. + +.BR selinux_check_passwd_access () +is used to check for a permission in the +.I passwd +class. +.BR selinux_check_passwd_access () +uses getprevcon() for the source and target security contexts. + +.BR checkPasswdAccess () +is a deprecated alias of the +.BR selinux_check_passwd_access () +function. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 on error. +. +.SH "SEE ALSO" +.BR selinux "(8), " getcon "(3), " getfilecon "(3), " get_ordered_context_list "(3)" diff --git a/man/man3/security_compute_av_flags.3 b/man/man3/security_compute_av_flags.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_av_flags.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_av_flags_raw.3 b/man/man3/security_compute_av_flags_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_av_flags_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_av_raw.3 b/man/man3/security_compute_av_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_av_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_create.3 b/man/man3/security_compute_create.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_create.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_create_name.3 b/man/man3/security_compute_create_name.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_create_name.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_create_name_raw.3 b/man/man3/security_compute_create_name_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_create_name_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_create_raw.3 b/man/man3/security_compute_create_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_create_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_member.3 b/man/man3/security_compute_member.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_member.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_member_raw.3 b/man/man3/security_compute_member_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_member_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_relabel.3 b/man/man3/security_compute_relabel.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_relabel.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_relabel_raw.3 b/man/man3/security_compute_relabel_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_relabel_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_user.3 b/man/man3/security_compute_user.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_user.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_compute_user_raw.3 b/man/man3/security_compute_user_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_compute_user_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_deny_unknown.3 b/man/man3/security_deny_unknown.3 new file mode 100644 index 0000000..d59e5c2 --- /dev/null +++ b/man/man3/security_deny_unknown.3 @@ -0,0 +1 @@ +.so man3/security_getenforce.3 diff --git a/man/man3/security_disable.3 b/man/man3/security_disable.3 new file mode 100644 index 0000000..072923c --- /dev/null +++ b/man/man3/security_disable.3 @@ -0,0 +1,30 @@ +.TH "security_disable" "3" "21 Nov 2009" "" "SELinux API documentation" +.SH "NAME" +security_disable \- disable the SELinux kernel code at runtime +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int security_disable(void);" +. +.SH "DESCRIPTION" +.BR security_disable () +disables the SELinux kernel code, unregisters selinuxfs from +.IR /proc/filesystems , +and then unmounts +.IR /sys/fs/selinux . +.sp +This function can only be called at runtime and prior to the initial policy +load. After the initial policy load, the SELinux kernel code cannot be disabled, +but only placed in "permissive" mode by using +.BR security_setenforce(3). +. +.SH "RETURN VALUE" +.BR security_disable () +returns zero on success or \-1 on error. +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia +. +.SH "SEE ALSO" +.BR selinux (8), " setenforce "(8) diff --git a/man/man3/security_get_boolean_active.3 b/man/man3/security_get_boolean_active.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/man/man3/security_get_boolean_active.3 @@ -0,0 +1 @@ +.so man3/security_load_booleans.3 diff --git a/man/man3/security_get_boolean_names.3 b/man/man3/security_get_boolean_names.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/man/man3/security_get_boolean_names.3 @@ -0,0 +1 @@ +.so man3/security_load_booleans.3 diff --git a/man/man3/security_get_boolean_pending.3 b/man/man3/security_get_boolean_pending.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/man/man3/security_get_boolean_pending.3 @@ -0,0 +1 @@ +.so man3/security_load_booleans.3 diff --git a/man/man3/security_get_initial_context.3 b/man/man3/security_get_initial_context.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_get_initial_context.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_get_initial_context_raw.3 b/man/man3/security_get_initial_context_raw.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/security_get_initial_context_raw.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/security_getenforce.3 b/man/man3/security_getenforce.3 new file mode 100644 index 0000000..f339b8b --- /dev/null +++ b/man/man3/security_getenforce.3 @@ -0,0 +1,56 @@ +.TH "security_getenforce" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_getenforce, security_setenforce, security_deny_unknown, security_reject_unknown, +security_get_checkreqprot \- get or set the enforcing state of SELinux +. +.SH "SYNOPSIS" +.B #include +.sp +.B int security_getenforce(void); +.sp +.BI "int security_setenforce(int "value ); +.sp +.B int security_deny_unknown(void); +.sp +.B int security_reject_unknown(void); +.sp +.B int security_get_checkreqprot(void); +. +.SH "DESCRIPTION" +.BR security_getenforce () +returns 0 if SELinux is running in permissive mode, 1 if it is running in +enforcing mode, and \-1 on error. + +.BR security_setenforce () +sets SELinux to enforcing mode if the value 1 is passed in, and sets it to +permissive mode if 0 is passed in. On success 0 is returned, on error \-1 is +returned. + +.BR security_deny_unknown () +returns 0 if SELinux treats policy queries on undefined object classes or +permissions as being allowed, 1 if such queries are denied, and \-1 on error. + +.BR security_reject_unknown () +returns 1 if the current policy was built with handle-unknown=reject and SELinux +would reject loading it, if it did not define all kernel object classes and +permissions. In this state, when +.BR selinux_set_mapping() +and +.BR selinux_check_access() +are used with an undefined userspace class or permission, an error is returned +and errno is set to EINVAL. + +It returns 0 if the current policy was built with handle-unknown=allow or +handle-unknown=deny. In this state, policy queries are treated according to +.BR security_deny_unknown(). +\-1 is returned on error. + +.BR security_get_checkreqprot () +can be used to determine whether SELinux is configured to check the +protection requested by the application or the actual protection that will +be applied by the kernel (including the effects of READ_IMPLIES_EXEC) on +mmap and mprotect calls. It returns 0 if SELinux checks the actual +protection, 1 if it checks the requested protection, and \-1 on error. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/security_load_booleans.3 b/man/man3/security_load_booleans.3 new file mode 100644 index 0000000..3b0bbea --- /dev/null +++ b/man/man3/security_load_booleans.3 @@ -0,0 +1,66 @@ +.TH "security_get_boolean_names" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API Documentation" +.SH "NAME" +security_load_booleans, security_set_boolean, security_commit_booleans, +security_get_boolean_names, security_get_boolean_active, +security_get_boolean_pending \- routines for manipulating SELinux boolean values +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int security_load_booleans(char *" path ");" +.sp +.BI "int security_get_boolean_names(char ***" names ", int *" len ");" +.sp +.BI "int security_get_boolean_pending(const char *" name ");" +.sp +.BI "int security_get_boolean_active(const char *" name ");" +.sp +.BI "int security_set_boolean(const char *" name ", int " value ");" +.sp +.BI "int security_set_boolean_list(size_t " boolcnt ", SELboolean *" boollist ", int " permanent ");" +.sp +.BI "int security_commit_booleans(void);" +. +.SH "DESCRIPTION" +The SELinux policy can include conditional rules that are enabled or +disabled based on the current values of a set of policy booleans. +These policy booleans allow runtime modification of the security +policy without having to load a new policy. + +The SELinux API allows for a transaction based update. So you can +set several boolean values and then commit them all at once. + +.BR security_load_booleans () +loads policy boolean settings. Path may be NULL, in which case the +booleans are loaded from the active policy boolean configuration file. + +.BR security_get_boolean_names () +provides a list of boolean names, currently supported by the loaded policy. + +.BR security_get_boolean_pending () +returns the pending value for boolean or \-1 on failure. + +.BR security_get_boolean_active () +returns the active value for boolean or \-1 on failure. + +.BR security_set_boolean () +sets the pending value for boolean + +.BR security_set_boolean_list () +saves a list of booleans in a single transaction. + +.BR security_commit_booleans () +commits all pending values for the booleans. +. +.SH "RETURN VALUE" +Where not otherwise stated, functions described in this manual page return +zero on success or \-1 on error. +. +.SH AUTHOR +This manual page was written by Dan Walsh . +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getsebool (8), +.BR booleans (8), +.BR togglesebool (8) diff --git a/man/man3/security_load_policy.3 b/man/man3/security_load_policy.3 new file mode 100644 index 0000000..af56163 --- /dev/null +++ b/man/man3/security_load_policy.3 @@ -0,0 +1,57 @@ +.TH "security_load_policy" "3" "3 November 2009" "guido@trentalancia.com" "SELinux API documentation" +.SH "NAME" +security_load_policy \- load a new SELinux policy +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int security_load_policy(void *" data ", size_t "len ); +.sp +.BI "int selinux_mkload_policy(int " preservebools ");" +.sp +.BI "int selinux_init_load_policy(int *" enforce ");" +. +.SH "DESCRIPTION" +.BR security_load_policy () +loads a new policy, returns 0 for success and \-1 for error. + +.BR selinux_mkload_policy () +makes a policy image and loads it. This function provides a higher level +interface for loading policy than +.BR \%security_load_policy (), +internally determining the right policy version, locating and opening +the policy file, mapping it into memory, manipulating it as needed for +current boolean settings and/or local definitions, and then calling +security_load_policy to load it. +.I preservebools +is a boolean flag indicating whether current policy boolean values should +be preserved into the new policy (if 1) or reset to the saved policy +settings (if 0). The former case is the default for policy reloads, while +the latter case is an option for policy reloads but is primarily used for +the initial policy load. +.BR selinux_init_load_policy () +performs the initial policy load. This function determines the desired +enforcing mode, sets the +.I enforce +argument accordingly for the caller to use, sets the SELinux kernel +enforcing status to match it, and loads the policy. It also internally +handles the initial selinuxfs mount required to perform these actions. +.sp +It should also be noted that after the initial policy load, the SELinux +kernel code cannot anymore be disabled and the selinuxfs cannot be +unmounted using a call to +.BR security_disable (3). +Therefore, after the initial policy load, the only operational changes +are those permitted by +.BR security_setenforce (3) +(i.e. eventually setting the framework in permissive mode rather than +in enforcing one). +. +.SH "RETURN VALUE" +Returns zero on success or \-1 on error. +. +.SH "AUTHOR" +This manual page has been written by Guido Trentalancia +. +.SH "SEE ALSO" +.BR selinux "(8), " security_disable "(3), " setenforce "(8) diff --git a/man/man3/security_mkload_policy.3 b/man/man3/security_mkload_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/man/man3/security_mkload_policy.3 @@ -0,0 +1 @@ +.so man3/security_load_policy.3 diff --git a/man/man3/security_policyvers.3 b/man/man3/security_policyvers.3 new file mode 100644 index 0000000..041ff3a --- /dev/null +++ b/man/man3/security_policyvers.3 @@ -0,0 +1,15 @@ +.TH "security_policyvers" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +security_policyvers \- get the version of the SELinux policy +.SH "SYNOPSIS" +.B #include +.sp +.B int security_policyvers(); +. +.SH "DESCRIPTION" +.BR security_policyvers () +returns the version of the policy (a positive integer) on success, or \-1 on +error. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/security_reject_unknown.3 b/man/man3/security_reject_unknown.3 new file mode 100644 index 0000000..d59e5c2 --- /dev/null +++ b/man/man3/security_reject_unknown.3 @@ -0,0 +1 @@ +.so man3/security_getenforce.3 diff --git a/man/man3/security_set_boolean.3 b/man/man3/security_set_boolean.3 new file mode 100644 index 0000000..29731ef --- /dev/null +++ b/man/man3/security_set_boolean.3 @@ -0,0 +1 @@ +.so man3/security_load_booleans.3 diff --git a/man/man3/security_setenforce.3 b/man/man3/security_setenforce.3 new file mode 100644 index 0000000..24bca10 --- /dev/null +++ b/man/man3/security_setenforce.3 @@ -0,0 +1 @@ +.so security_getenforce.3 diff --git a/man/man3/selabel_close.3 b/man/man3/selabel_close.3 new file mode 100644 index 0000000..468fdaf --- /dev/null +++ b/man/man3/selabel_close.3 @@ -0,0 +1 @@ +.so man3/selabel_open.3 diff --git a/man/man3/selabel_digest.3 b/man/man3/selabel_digest.3 new file mode 100644 index 0000000..56a008f --- /dev/null +++ b/man/man3/selabel_digest.3 @@ -0,0 +1,61 @@ +.TH "selabel_digest" "3" "16 Sept 2015" "" "SELinux API documentation" +.SH "NAME" +selabel_digest \- Return digest of specfiles and list of files used +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int selabel_digest(struct selabel_handle *" hnd , +.in +\w'int selabel_digest('u +.BI "unsigned char **" digest , +.BI "size_t *" digest_len , +.br +.BI "char ***" specfiles, +.BI "size_t *" num_specfiles ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_digest () +performs an operation on the handle +.IR hnd , +returning the results of the SHA1 digest pointed to by +.IR digest , +whose length will be +.IR digest_len . +The list of specfiles used in the SHA1 digest calculation is returned in +.I specfiles +with the number of entries in +.IR num_specfiles . +.sp +To enable +.BR selabel_digest () +to return this information the +.B SELABEL_OPT_DIGEST +option must be enable in +.BR selabel_open (3). +.sp +The result of +.BR selabel_digest () +must not be used after +.BR selabel_close (3). +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +No digest available (returned if +.B SELABEL_OPT_DIGEST +option not enabled). +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selinux (8) diff --git a/man/man3/selabel_lookup.3 b/man/man3/selabel_lookup.3 new file mode 100644 index 0000000..4e47c3e --- /dev/null +++ b/man/man3/selabel_lookup.3 @@ -0,0 +1,79 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_lookup" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_lookup \- obtain SELinux security context from a string label +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" key ", int " type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_raw('u +.BI "char **" context , +.br +.BI "const char *" key ", int " type ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_lookup () +performs a lookup operation on the handle +.IR hnd , +returning the result in the memory pointed to by +.IR context , +which must be freed by the caller using +.BR freecon (3). +The +.I key +and +.I type +parameters are the inputs to the lookup operation and are interpreted according to the specific backend that +.I handle +is open on. + +.BR selabel_lookup_raw () +behaves identically to +.BR selabel_lookup () +but does not perform context translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOENT +No context corresponding to the input +.I key +and +.I type +was found. +.TP +.B EINVAL +The +.I key +and/or +.I type +inputs are invalid, or the context being returned failed validation. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8) diff --git a/man/man3/selabel_lookup_best_match.3 b/man/man3/selabel_lookup_best_match.3 new file mode 100644 index 0000000..ef2efb4 --- /dev/null +++ b/man/man3/selabel_lookup_best_match.3 @@ -0,0 +1,100 @@ +.TH "selabel_lookup_best_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selabel_lookup_best_match \- obtain a best match SELinux security +context \- Only supported on file backend. +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "int selabel_lookup_best_match(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_best_match('u +.BI "char **" context , +.br +.BI "const char *" key , +.br +.BI "const char **" links , +.br +.BI "int " type ");" +.in +.sp +.BI "int selabel_lookup_best_match_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup_best_match_raw('u +.BI "char **" context , +.br +.BI "const char *" key , +.br +.BI "const char **" links , +.br +.BI "int " type ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_lookup_best_match () +performs a best match lookup operation on the handle +.IR hnd , +returning the result in the memory pointed to by +.IR context , +which must be freed by the caller using +.BR freecon (3). +The \fIkey\fR parameter is a file path to check for best match using zero or +more \fIlink\fR (aliases) parameters. The order of precedence for best match is: +.RS +.IP "1." 4 +An exact match for the real path (\fIkey\fR) or +.IP "2." 4 +An exact match for any of the \fIlink\fRs (aliases), or +.IP "3." 4 +The longest fixed prefix match. +.RE +.sp +The \fItype\fR parameter is an optional file \fImode\fR argument that should +be set to the mode bits of the file, as determined by \fBlstat\fR(2). +\fImode\fR may be zero, however full matching may not occur. + +.BR selabel_lookup_best_match_raw () +behaves identically to +.BR selabel_lookup_best_match () +but does not perform context translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B ENOENT +No context corresponding to the input +.I key +and +.I type +was found. +.TP +.B EINVAL +The +.I key +and/or +.I type +inputs are invalid, or the context being returned failed validation. +.TP +.B ENOMEM +An attempt to allocate memory failed. +.sp +.SH "NOTES" +Example usage - When a service creates a device node, it may also create one +or more symlinks to the device node. These symlinks may be the only stable +name for the device, e.g. if the partition is dynamically assigned. +The file label backend supports this by looking up the "best match" +for a device node based on its real path (\fIkey\fR) and any \fIlink\fRs to it +(aliases). The order of precedence for best match is described above. +.sp +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8), +.BR lstat (2), +.BR selabel_file (5) diff --git a/man/man3/selabel_lookup_best_match_raw.3 b/man/man3/selabel_lookup_best_match_raw.3 new file mode 100644 index 0000000..8982f17 --- /dev/null +++ b/man/man3/selabel_lookup_best_match_raw.3 @@ -0,0 +1 @@ +.so man3/selabel_lookup_best_match.3 diff --git a/man/man3/selabel_lookup_raw.3 b/man/man3/selabel_lookup_raw.3 new file mode 100644 index 0000000..64e003e --- /dev/null +++ b/man/man3/selabel_lookup_raw.3 @@ -0,0 +1 @@ +.so man3/selabel_lookup.3 diff --git a/man/man3/selabel_open.3 b/man/man3/selabel_open.3 new file mode 100644 index 0000000..971ebc1 --- /dev/null +++ b/man/man3/selabel_open.3 @@ -0,0 +1,108 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_open" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_open, selabel_close \- userspace SELinux labeling interface +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "struct selabel_handle *selabel_open(int " backend , +.in +\w'struct selabel_handle *selabel_open('u +.BI "const struct selinux_opt *" options , +.br +.BI "unsigned " nopt ");" +.in +.sp +.BI "void selabel_close(struct selabel_handle *" hnd ");" +. +.SH "DESCRIPTION" +.BR selabel_open () +is used to initialize a labeling handle to be used for lookup operations. The +.I backend +argument specifies which backend is to be opened; the list of current backends appears in +.B BACKENDS +below. + +The +.I options +argument should be NULL or a pointer to an array of +.B selinux_opt +structures of length +.IR nopt : + +.RS +.ta 4n 16n 24n +.nf +struct selinux_opt { + int type; + const char *value; +}; +.fi +.ta +.RE + +The available option types are described in +.B GLOBAL OPTIONS +below as well as in the documentation for each individual backend. The return value on success is a non-NULL value for use in subsequent label operations. + +.BR selabel_close () +terminates use of a handle, freeing any internal resources associated with it. After this call has been made, the handle must not be used again. +. +.SH "GLOBAL OPTIONS" +Global options which may be passed to +.BR selabel_open () +include the following: +. +.TP +.B SELABEL_OPT_UNUSED +The option with a type code of zero is a no-op. Thus an array of options may be initizalized to zero and any untouched elements will not cause an error. +.TP +.B SELABEL_OPT_VALIDATE +A non-null value for this option enables context validation. By default, +.BR security_check_context (3) +is used; a custom validation function can be provided via +.BR selinux_set_callback (3). +Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation. +.TP +.B SELABEL_OPT_DIGEST +A non-null value for this option enables the generation of an SHA1 digest of +the spec files loaded as described in +.BR selabel_digest (3) +. +.SH "BACKENDS" +.TP +.B SELABEL_CTX_FILE +File contexts backend, described in +.BR selabel_file (5). +.TP +.B SELABEL_CTX_MEDIA +Media contexts backend, described in +.BR selabel_media (5). +.TP +.B SELABEL_CTX_X +X Windows contexts backend, described in +.BR selabel_x (5). +.TP +.B SELABEL_CTX_DB +Database objects contexts backend, described in +.BR selabel_db (5). +. +.SH "RETURN VALUE" +A non-NULL handle value is returned on success. On error, NULL is returned and +.I errno +is set appropriately. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.ad l +.nh +.BR selabel_lookup (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8) diff --git a/man/man3/selabel_partial_match.3 b/man/man3/selabel_partial_match.3 new file mode 100644 index 0000000..4cd46f7 --- /dev/null +++ b/man/man3/selabel_partial_match.3 @@ -0,0 +1,34 @@ +.TH "selabel_partial_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selabel_partial_match \- determine whether a direct or partial match is +possible on a file path \- Only supported on file backend. +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.br +.B #include +.sp +.BI "bool selabel_partial_match(struct selabel_handle *" hnd , +.in +\w'int selabel_partial_match('u +.BI "const char *" key ");" +.in +. +.SH "DESCRIPTION" +.BR selabel_partial_match () +performs a partial match operation on the handle +.IR hnd , +returning TRUE or FALSE. +The \fIkey\fR parameter is a file path to check for a direct or partial match. +.sp +.SH "RETURN VALUE" +TRUE is returned if a direct or partial match is found, FALSE if not. +.sp +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_stats (3), +.BR selinux_set_callback (3), +.BR selinux (8), +.BR selabel_file (5) diff --git a/man/man3/selabel_stats.3 b/man/man3/selabel_stats.3 new file mode 100644 index 0000000..44e1a65 --- /dev/null +++ b/man/man3/selabel_stats.3 @@ -0,0 +1,35 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_stats" "3" "18 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selabel_stats \- obtain SELinux labeling statistics +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "void selabel_stats(struct selabel_handle *" hnd ");" +. +.SH "DESCRIPTION" +.BR selabel_stats () +causes zero or more messages to be printed containing backend-specific information about number of queries performed, number of unused entries, or other operational information. + +The messages are printed to standard error by default; a custom logging function can be provided via +.BR selinux_set_callback (3). +. +.SH "RETURN VALUE" +None. +. +.SH "ERRORS" +None. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR selabel_lookup (3), +.BR selinux_set_callback (3), +.BR selinux (8) diff --git a/man/man3/selinux_binary_policy_path.3 b/man/man3/selinux_binary_policy_path.3 new file mode 100644 index 0000000..edaa3b8 --- /dev/null +++ b/man/man3/selinux_binary_policy_path.3 @@ -0,0 +1,115 @@ +.TH "selinux_binary_policy_path" "3" "15 November 2004" "dwalsh@redhat.com" "SELinux API Documentation" +.SH "NAME" +selinux_path, selinux_policy_root, selinux_binary_policy_path, selinux_current_policy_path, +selinux_failsafe_context_path, selinux_removable_context_path, +selinux_default_context_path, selinux_user_contexts_path, +selinux_file_context_path, selinux_media_context_path, +selinux_contexts_path, selinux_booleans_path \- These functions return the paths to the active SELinux policy configuration +directories and files +. +.SH "SYNOPSIS" +.B #include +.sp + +.B const char *selinux_path(void); +.sp +.B const char *selinux_policy_root(void); +.sp +.B const char *selinux_binary_policy_path(void); +.sp +.B const char *selinux_current_policy_path(void); +.sp +.B const char *selinux_failsafe_context_path(void); +.sp +.B const char *selinux_removable_context_path(void); +.sp +.B const char *selinux_default_context_path(void); +.sp +.B const char *selinux_user_contexts_path(void); +.sp +.B const char *selinux_usersconf_path(void); +.sp +.B const char *selinux_x_context_path(void); +.sp +.B const char *selinux_sepgsql_context_path(void); +.sp +.B const char *selinux_file_context_path(void); +.sp +.B const char *selinux_media_context_path(void); +.sp +.B const char *selinux_securetty_types_path(void); +.sp +.B const char *selinux_contexts_path(void); +.sp +.B const char *selinux_booleans_path(void); +. +.SH "DESCRIPTION" +These functions return the paths to the active policy configuration +directories and files based on the settings in +.IR /etc/selinux/config . +.sp +.BR selinux_path () +returns the top-level SELinux configuration directory. +.sp +.BR selinux_policy_root () +returns the top-level policy directory. +.sp +.BR selinux_binary_policy_path () +returns the binary policy file loaded into kernel. +.sp +.BR selinux_current_policy_path () +returns the currently loaded policy file from the kernel. +.sp +.BR selinux_default_type_path () +returns the context file mapping roles to default types. +.sp +.BR selinux_failsafe_context_path () +returns the failsafe context for emergency logins. +.sp +.BR selinux_removable_context_path () +returns the filesystem context for removable media. +.sp +.BR selinux_default_context_path () +returns the system-wide default contexts for user sessions. +.sp +.BR selinux_user_contexts_path () +returns the directory containing per-user default contexts. +.sp +.BR selinux_usersconf_path () +returns the file containing mapping between Linux Users and SELinux users. +.sp +.BR selinux_x_context_path () +returns the file containing configuration for XSELinux extension. +.sp +.BR selinux_sepgsql_context_path () +returns the file containing configuration for SE-PostgreSQL. +.sp +.BR selinux_netfilter_context_path () +returns the default netfilter context. +.sp +.BR selinux_file_context_path () +returns the default system file contexts configuration. +.sp +.BR selinux_file_context_local_path () +returns the local customization file contexts configuration. +.sp +.BR selinux_file_context_homedir_path () +returns the home directory file contexts configuration. +.sp +.BR selinux_media_context_path () +returns the file contexts for media device nodes. +.sp +.BR selinux_contexts_path () +returns the directory containing all of the context configuration files. +.sp +.BR selinux_securetty_types_path () +returns the defines tty types for newrole securettys. +.sp +.BR selinux_booleans_path () +returns the initial policy boolean settings. +. +.SH AUTHOR +This manual page was written by Dan Walsh . +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_boolean_sub.3 b/man/man3/selinux_boolean_sub.3 new file mode 100644 index 0000000..a29a38d --- /dev/null +++ b/man/man3/selinux_boolean_sub.3 @@ -0,0 +1,29 @@ +.TH "selinux_boolean_sub" "3" "11 June 2012" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_boolean_sub \- Search the translated name for a boolean_name record +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "char *selinux_boolean_sub(const char *" boolean_name ");" +.sp +.SH "DESCRIPTION" +.BR selinux_boolean_sub () +searches the +.I \%/etc/selinux/{POLICYTYPE}/booleans.subs_dist +file +for a matching boolean_name record. If the record exists the boolean substitution name is returned. If not +.BR \%selinux_boolean_sub () +returns the original +.IR \%boolean_name . + +.SH "RETURN VALUE" +.BR selinux_boolean_sub () +returns the +.I boolean_name +or the substituted name on success. The returned value must be freed with +.BR free "(3)." +.BR selinux_boolean_sub () +returns NULL on error. +.SH "SEE ALSO" +.BR security_get_boolean_names (3) diff --git a/man/man3/selinux_booleans_path.3 b/man/man3/selinux_booleans_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_booleans_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_check_access.3 b/man/man3/selinux_check_access.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/selinux_check_access.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/selinux_check_passwd_access.3 b/man/man3/selinux_check_passwd_access.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/man/man3/selinux_check_passwd_access.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/man/man3/selinux_check_securetty_context.3 b/man/man3/selinux_check_securetty_context.3 new file mode 100644 index 0000000..429023b --- /dev/null +++ b/man/man3/selinux_check_securetty_context.3 @@ -0,0 +1,16 @@ +.TH "selinux_check_securetty_context" "3" "1 January 2007" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_check_securetty_context \- check whether a SELinux tty security context is defined as a securetty context +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_check_securetty_context(char *" tty_context ); +. +.SH "DESCRIPTION" +.BR selinux_check_securetty_context () +returns 0 if tty_context is a securetty context, +returns < 0 otherwise. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_colors_path.3 b/man/man3/selinux_colors_path.3 new file mode 100644 index 0000000..cc57e43 --- /dev/null +++ b/man/man3/selinux_colors_path.3 @@ -0,0 +1,37 @@ +.TH "selinux_colors_path" "3" "08 April 2011" "SELinux API documentation" +.SH "NAME" +selinux_colors_path \- Return a path to the active SELinux policy color configuration file +. +.SH "SYNOPSIS" +.B #include +.sp +.B const char *selinux_colors_path(void); +. +.SH "DESCRIPTION" +.BR selinux_colors_path () +returns the path to the active policy color configuration file. +.sp +The path is built from the path returned by +.BR selinux_policy_root "(3)" +with +.I /secolor.conf +appended. +.sp +This optional configuration file whose format is shown in +.BR \%secolor.conf (5), +controls the colors to be associated with the +.I raw +context components of the +.BR selinux_raw_context_to_color "(3)" +function when information is to be displayed by an SELinux color-aware application. +. +.SH "RETURN VALUE" +On success, the path to the active policy color configuration file is returned. If a path is not available NULL is returned. +. +.SH "ERRORS" +None. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_policy_root "(3), " selinux_config "(5), " selinux_raw_context_to_color "(3), " secolor.conf "(5)" diff --git a/man/man3/selinux_contexts_path.3 b/man/man3/selinux_contexts_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_contexts_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_current_policy_path.3 b/man/man3/selinux_current_policy_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_current_policy_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_default_context_path.3 b/man/man3/selinux_default_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_default_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_default_type_path.3 b/man/man3/selinux_default_type_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_default_type_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_failsafe_context_path.3 b/man/man3/selinux_failsafe_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_failsafe_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_file_context_cmp.3 b/man/man3/selinux_file_context_cmp.3 new file mode 100644 index 0000000..6d4b3e8 --- /dev/null +++ b/man/man3/selinux_file_context_cmp.3 @@ -0,0 +1,74 @@ +.TH "selinux_file_context_cmp" "3" "08 March 2011" "SELinux API documentation" +.SH "NAME" +selinux_file_context_cmp \- Compare two SELinux security contexts excluding the 'user' component +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_file_context_cmp(const char *" a ", " +.RS +.BI "const char *" b ");" +.RE +. +.SH "DESCRIPTION" +.BR selinux_file_context_cmp () +compares two context strings excluding the user component with +.BR strcmp (3) +as shown in the +.B EXAMPLE +section. +.sp +This is useful as for most object contexts, the user component is not relevant. +. +.SH "RETURN VALUE" +The return values follow the +.BR strcmp (3) +function, where: +.RS +0 if they are equal. +.RE +.RS +1 if +.I a +is greater than +.I b +.RE +.RS +\-1 if +.I a +is less than +.I b +.RE +. +.SH "ERRORS" +None. +. +.SH "NOTES" +The contexts being compared do not specifically need to be file contexts. +. +.SH "EXAMPLE" +If context +.I a +is: +.RS +user_u:user_r:user_t:s0 +.RE +.sp +and context +.I b +is: +.RS +root:user_r:user_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:user_r:user_t:s0 and :user_r:user_t:s0 +.RE +.sp +Therefore they will match and +.BR selinux_file_context_cmp () +will return zero. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_file_context_homedir_path.3 b/man/man3/selinux_file_context_homedir_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_file_context_homedir_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_file_context_local_path.3 b/man/man3/selinux_file_context_local_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_file_context_local_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_file_context_path.3 b/man/man3/selinux_file_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_file_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_file_context_verify.3 b/man/man3/selinux_file_context_verify.3 new file mode 100644 index 0000000..893949f --- /dev/null +++ b/man/man3/selinux_file_context_verify.3 @@ -0,0 +1,101 @@ +.TH "selinux_file_context_verify" "3" "08 March 2011" "SELinux API documentation" +.SH "NAME" +selinux_file_context_verify \- Compare the SELinux security context on disk to the default security context required by the policy file contexts file +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");" +. +.SH "DESCRIPTION" +.BR selinux_file_context_verify () +compares the context of the specified +.I path +that is held on disk (in the extended attribute), to the system default entry held in the file contexts series of files. +.sp +The +.I mode +may be zero. +.sp +Note that the two contexts are compared for "significant" differences (i.e. the user component of the contexts are ignored) as shown in the +.B EXAMPLE +section. +. +.SH "RETURN VALUE" +If the contexts significantly match, 1 (one) is returned. +.sp +If the contexts do not match 0 (zero) is returned and +.I errno +is set to either +.B ENOENT +or +.B EINVAL +for the reasons listed in the +.B ERRORS +section, or if +.I errno += 0 then the contexts did not match. +.sp +On failure \-1 is returned and +.I errno +set appropriately. +. +.SH "ERRORS" +.TP +.B ENOTSUP +if extended attributes are not supported by the file system. +.TP +.B ENOENT +if there is no entry in the file contexts series of files or +.I path +does not exist. +.TP +.B EINVAL +if the entry in the file contexts series of files or +.I path +are invalid, or the returned context fails validation. +.TP +.B ENOMEM +if attempt to allocate memory failed. +. +.SH "FILES" +The following configuration files (the file contexts series of files) supporting the active policy will be used (should they exist) to determine the +.I path +default context: +.sp +.RS +.I contexts/files/file_contexts +- This file must exist. +.sp +.I contexts/files/file_contexts.local +- If exists has local customizations. +.sp +.I contexts/files/file_contexts.homedirs +- If exists has users home directory customizations. +.sp +.I contexts/files/file_contexts.subs +- If exists has substitutions that are then applied to the 'in memory' version of the file contexts files. +.RE +. +.SH "EXAMPLE" +If the files context is: +.RS +unconfined_u:object_r:admin_home_t:s0 +.RE +.sp +and the default context defined in the file contexts file is: +.RS +system_u:object_r:admin_home_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:object_r:admin_home_t:s0 and :object_r:admin_home_t:s0 +.RE +.sp +Therefore they will match and +.BR selinux_file_context_verify () +will return 1. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_getenforcemode.3 b/man/man3/selinux_getenforcemode.3 new file mode 100644 index 0000000..7ed94c1 --- /dev/null +++ b/man/man3/selinux_getenforcemode.3 @@ -0,0 +1,31 @@ +.TH "selinux_getenforcemode" "3" "25 May 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_getenforcemode \- get the enforcing state of SELinux +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_getenforcemode(int *" enforce ); +. +.SH "DESCRIPTION" +.BR selinux_getenforcemode () +Reads the contents of the +.I /etc/selinux/config +file to determine how the system was setup to run SELinux. + +Sets the value of +.I enforce +to 1 if SELinux should be run in enforcing mode. +Sets the value of +.I enforce +to 0 if SELinux should be run in permissive mode. +Sets the value of +.I enforce +to \-1 if SELinux should be disabled. +. +.SH "RETURN VALUE" +On success, zero is returned. +On failure, \-1 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_getpolicytype.3 b/man/man3/selinux_getpolicytype.3 new file mode 100644 index 0000000..b219d42 --- /dev/null +++ b/man/man3/selinux_getpolicytype.3 @@ -0,0 +1,26 @@ +.TH "selinux_getpolicytype" "3" "24 Sep 2008" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_getpolicytype \- get the type of SELinux policy running on the system +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_getpolicytype(char **" policytype ); +. +.SH "DESCRIPTION" +.BR selinux_getpolicytype () +Reads the contents of the +.I /etc/selinux/config +file to determine the SELinux policy used on the system, and sets +.I \%policytype +accordingly. Free +.I \%policytype +with +.BR free (3). +. +.SH "RETURN VALUE" +On success, zero is returned. +On failure, \-1 is returned. +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_homedir_context_path.3 b/man/man3/selinux_homedir_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_homedir_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_init_load_policy.3 b/man/man3/selinux_init_load_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/man/man3/selinux_init_load_policy.3 @@ -0,0 +1 @@ +.so man3/security_load_policy.3 diff --git a/man/man3/selinux_lsetfilecon_default.3 b/man/man3/selinux_lsetfilecon_default.3 new file mode 100644 index 0000000..d4fc658 --- /dev/null +++ b/man/man3/selinux_lsetfilecon_default.3 @@ -0,0 +1,20 @@ +.TH "selinux_lsetfilecon_default" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +selinux_lsetfilecon_default \- set the file context to the system defaults +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_lsetfilecon_default(const char *" path ");" +. +.SH "DESCRIPTION" +.BR selinux_lsetfilecon_default () +sets the file context to the system defaults. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_file_context_cmp "(3), " selinux_file_context_verify "(3), " matchpathcon "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/selinux_media_context_path.3 b/man/man3/selinux_media_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_media_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_mkload_policy.3 b/man/man3/selinux_mkload_policy.3 new file mode 100644 index 0000000..94e8117 --- /dev/null +++ b/man/man3/selinux_mkload_policy.3 @@ -0,0 +1 @@ +.so man3/security_load_policy.3 diff --git a/man/man3/selinux_netfilter_context_path.3 b/man/man3/selinux_netfilter_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_netfilter_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_path.3 b/man/man3/selinux_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_policy_root.3 b/man/man3/selinux_policy_root.3 new file mode 100644 index 0000000..75ac8ec --- /dev/null +++ b/man/man3/selinux_policy_root.3 @@ -0,0 +1,34 @@ +.TH "selinux_policy_root" "3" "25 May 2004" "dwalsh@redhat.com" "SELinux API documentation" +.SH "NAME" +selinux_policy_root \- return the path of the SELinux policy files for this machine +selinux_set_policy_root \- Set an alternate SELinux root path for the SELinux policy files for this machine. +. +.SH "SYNOPSIS" +.B #include +.sp +.B const char *selinux_policy_root(void); +. +.sp +.B int selinux_set_policy_root(const char *policypath); +. +.SH "DESCRIPTION" +.BR selinux_policy_root () +reads the contents of the +.I /etc/selinux/config +file to determine which policy files should be used for this machine. +. +.BR selinux_set_policy_root () +sets up all policy paths based on the alternate root + +.I /etc/selinux/config +file to determine which policy files should be used for this machine. +. +.SH "RETURN VALUE" +On success, selinux_policy_root returns a directory path containing the SELinux policy files. +On failure, selinux_policy_root returns NULL. + +On success, selinux_set_policy_root returns 0 on success -1 on failure. + +. +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/man/man3/selinux_raw_context_to_color.3 b/man/man3/selinux_raw_context_to_color.3 new file mode 100644 index 0000000..cfd564d --- /dev/null +++ b/man/man3/selinux_raw_context_to_color.3 @@ -0,0 +1,123 @@ +.TH "selinux_raw_context_to_color" "3" "08 April 2011" "SELinux API documentation" +.SH "NAME" +selinux_raw_context_to_color \- Return RGB color string for an SELinux security context +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_raw_context_to_color(char *" raw ", " +.RS +.BI "char **" color_str ");" +.RE +. +.SH "DESCRIPTION" +.BR selinux_raw_context_to_color () +returns a +.I color_str +associated to the raw context +.I raw +provided that the +.BR mcstransd "(8)" +daemon is running, the policy is an MLS type policy (MCS or MLS) and there is a color configuration file +.BR \%secolor.conf (5) +(see the +.B FILES +section). +.sp +The +.I color_str +string is a space separated list of eight hexadecimal RGB triples, each prefixed by a hash character (#). These represent the user:role:type:range components of the foreground and background colors. An example string is shown in the +.B EXAMPLE +section. + +The returned +.I color_str +string must be freed with +.BR free "(3)." + +If a color has not been configured for a specific user, role, type and/or range component of context +.IR raw "," +then +.BR \%selinux_raw_context_to_color () +will select the color returned in +.I color_str +in order of precedence as follows: +.RS +role, type, range +.br +user, type, range +.br +user, role, range +.br +user, role, type +.br +.RE + +If there are no entries in the +.BR secolor.conf (5) +file for any of the components of context +.I raw +(or the file is not present), then the default string returned in +.I color_str +is: +.sp +.RS +----- user ---- ---- role ---- ---- type ---- ---- range ---- +.br +#000000 #ffffff #000000 #ffffff #000000 #ffffff #000000 #ffffff +.sp +.RE +. +.SH "RETURN VALUE" +On success, zero is returned. +.br +On failure, \-1 is returned with +.I errno +set appropriately. +. +.SH "ERRORS" +.B ENOENT +If the +.BR mcstransd "(8)" +daemon is not running. +. +.SH "FILES" +.BR selinux_raw_context_to_color () +obtains the translated entry from the active policy +.BR secolor.conf "(5)" +file as returned by +.BR \%selinux_colors_path (3). +The file format is described in +.BR \%secolor.conf (5). +. +.SH "NOTES" +1. The primary use of +.BR selinux_raw_context_to_color () +is to return a color that corresponds to a range, that can then be used to highlight information at different MLS levels. +.sp +2. The +.BR mcstransd "(8)" +daemon process security level must dominate the +.I raw +security level passed to it by the +.BR selinux_raw_context_to_color () +function. If not, the range color selected will be as defined by the order of precedence. +. +.SH "EXAMPLE" +.BR selinux_raw_context_to_color () +returns the foreground and background colors of the context string components (user:role:type:range) as RGB triples as follows: +.sp + + user : role : type : range +.br + fg bg : fg bg : fg bg : fg bg +.br +#000000 #ffffff #ffffff #000000 #d2b48c #ffa500 #000000 #008000 +.br + black white : white black : tan orange : black green +.br +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_colors_path "(3), " mcstransd "(8), " secolor.conf "(5), " selinux_raw_to_trans_context "(3), " selinux_trans_to_raw_context "(3), " free "(3)" diff --git a/man/man3/selinux_removable_context_path.3 b/man/man3/selinux_removable_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_removable_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_restorecon.3 b/man/man3/selinux_restorecon.3 new file mode 100644 index 0000000..1eac6ed --- /dev/null +++ b/man/man3/selinux_restorecon.3 @@ -0,0 +1,252 @@ +.TH "selinux_restorecon" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon \- restore file(s) default SELinux security contexts +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_restorecon(const char *" pathname , +.in +\w'int selinux_restorecon('u +.br +.BI "unsigned int " restorecon_flags ");" +.in +. +.SH "DESCRIPTION" +.BR selinux_restorecon () +restores file default security contexts on filesystems that support extended +attributes (see +.BR xattr (7)), +based on: +.sp +.RS +.IR pathname +containing a directory or file to be relabeled. +.br +If this is a directory and the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +has been set (for descending through directories), then +.BR selinux_restorecon () +will write an SHA1 digest of the combined specfiles (see the +.B NOTES +section for details) to an extended attribute of +.IR security.restorecon_last +once the relabeling has been completed successfully. This digest will be +checked should +.BR selinux_restorecon () +be rerun +with the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +flag set. If any of the specfiles had been updated, the digest +will also be updated. However if the digest is the same, no relabeling checks +will take place (unless the +.B SELINUX_RESTORECON_IGNORE_DIGEST +flag is set). +.sp +.IR restorecon_flags +contains the labeling option/rules as follows: +.sp +.RS +.sp +.B SELINUX_RESTORECON_IGNORE_DIGEST +force the checking of labels even if the stored SHA1 digest matches the +specfiles SHA1 digest. The specfiles digest will be written to the +.IR security.restorecon_last +extended attribute once relabeling has been completed successfully provided the +.B SELINUX_RESTORECON_NOCHANGE +flag has not been set. +.sp +.B SELINUX_RESTORECON_NOCHANGE +don't change any file labels (passive check) or update the digest in the +.IR security.restorecon_last +extended attribute. +.sp +.B SELINUX_RESTORECON_SET_SPECFILE_CTX +If set, reset the files label to match the default specfile context. +If not set only reset the files "type" component of the context to match the +default specfile context. +.sp +.B SELINUX_RESTORECON_RECURSE +change file and directory labels recursively (descend directories) +and if successful write an SHA1 digest of the combined specfiles to an +extended attribute as described in the +.B NOTES +section. +.sp +.B SELINUX_RESTORECON_VERBOSE +log file label changes. +.RS +Note that if +.B SELINUX_RESTORECON_VERBOSE +and +.B SELINUX_RESTORECON_PROGRESS +flags are set, then +.B SELINUX_RESTORECON_PROGRESS +will take precedence. +.RE +.sp +.B SELINUX_RESTORECON_PROGRESS +show progress by outputting the number of files in 1k blocks processed +to stdout. If the +.B SELINUX_RESTORECON_MASS_RELABEL +flag is also set then the approximate percentage complete will be shown. +.sp +.B SELINUX_RESTORECON_MASS_RELABEL +generally set when relabeling the entire OS, that will then show the +approximate percentage complete. The +.B SELINUX_RESTORECON_PROGRESS +flag must also be set. +.sp +.B SELINUX_RESTORECON_REALPATH +convert passed-in +.I pathname +to the canonical pathname using +.BR realpath (3). +.sp +.B SELINUX_RESTORECON_XDEV +prevent descending into directories that have a different device number than +the +.I pathname +entry from which the descent began. +.sp +.B SELINUX_RESTORECON_ADD_ASSOC +attempt to add an association between an inode and a specification. If there +is already an association for the inode and it conflicts with the +specification, then use the last matching specification. +.sp +.B SELINUX_RESTORECON_ABORT_ON_ERROR +abort on errors during the file tree walk. +.sp +.B SELINUX_RESTORECON_SYSLOG_CHANGES +log any label changes to +.BR syslog (3). +.sp +.B SELINUX_RESTORECON_LOG_MATCHES +log what specfile context matched each file. +.sp +.B SELINUX_RESTORECON_IGNORE_NOENTRY +ignore files that do not exist. +.sp +.B SELINUX_RESTORECON_IGNORE_MOUNTS +do not read +.B /proc/mounts +to obtain a list of non-seclabel mounts to be excluded from relabeling checks. +.br +Setting +.B SELINUX_RESTORECON_IGNORE_MOUNTS +is useful where there is a non-seclabel fs mounted with a seclabel fs mounted +on a directory below this. +.RE +.sp +The behavior regarding the checking and updating of the SHA1 digest described +above is the default behavior. It is possible to change this by first calling +.BR selabel_open (3) +and not enabling the +.B SELABEL_OPT_DIGEST +option, then calling +.BR selinux_restorecon_set_sehandle (3) +to set the handle to be used by +.BR selinux_restorecon (3). +.sp +If the +.I pathname +is a directory path, then it is possible to set directories to be excluded +from the path by calling +.BR selinux_restorecon_set_exclude_list (3) +with a +.B NULL +terminated list before calling +.BR selinux_restorecon (3). +.sp +By default +.BR selinux_restorecon (3) +reads +.B /proc/mounts +to obtain a list of non-seclabel mounts to be excluded from relabeling checks +unless the +.B SELINUX_RESTORECON_IGNORE_MOUNTS +flag has been set. +.RE +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "NOTES" +.IP "1." 4 +To improve performance when relabeling file systems recursively (e.g. the +.IR restorecon_flags +.B SELINUX_RESTORECON_RECURSE +flag is set) +.BR selinux_restorecon () +will write an SHA1 digest of the specfiles that are processed by +.BR selabel_open (3) +to an extended attribute named +.IR security.restorecon_last +to the directory specified in the +.IR pathname . +.IP "2." 4 +To check the extended attribute entry use +.BR getfattr (1) , +for example: +.sp +.RS +.RS +getfattr -e hex -n security.restorecon_last / +.RE +.RE +.IP "3." 4 +The SHA1 digest is calculated by +.BR selabel_open (3) +concatenating the specfiles it reads during initialisation with the +resulting digest and list of specfiles being retrieved by +.BR selabel_digest (3). +.IP "4." 4 +The specfiles consist of the mandatory +.I file_contexts +file plus any subs, subs_dist, local and homedir entries (text or binary versions) +as determined by any +.BR selabel_open (3) +options e.g. +.BR SELABEL_OPT_BASEONLY . +.sp +Should any of the specfiles have changed, then when +.BR selinux_restorecon () +is run again with the +.B SELINUX_RESTORECON_RECURSE +flag set, a new SHA1 digest will be calculated and all files will be automatically +relabeled depending on the settings of the +.B SELINUX_RESTORECON_SET_SPECFILE_CTX +flag (provided +.B SELINUX_RESTORECON_NOCHANGE +is not set). +.IP "5." 4 +.B /sys +and in-memory filesystems do not support the +.IR security.restorecon_last +extended attribute and are automatically excluded from any relabeling checks. +.IP "6." 4 +By default +.B stderr +is used to log output messages and errors. This may be changed by calling +.BR selinux_set_callback (3) +with the +.B SELINUX_CB_LOG +.I type +option. +. +.SH "SEE ALSO" +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_set_alt_rootpath (3), +.br +.BR selinux_restorecon_xattr (3), +.br +.BR selinux_set_callback (3) diff --git a/man/man3/selinux_restorecon_default_handle.3 b/man/man3/selinux_restorecon_default_handle.3 new file mode 100644 index 0000000..52f5ad3 --- /dev/null +++ b/man/man3/selinux_restorecon_default_handle.3 @@ -0,0 +1,63 @@ +.TH "selinux_restorecon_default_handle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_default_handle \- sets default parameters for +.BR selinux_restorecon (3) +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.B "struct selabel_handle *selinux_restorecon_default_handle(void);" +. +.SH "DESCRIPTION" +.BR selinux_restorecon_default_handle () +sets default parameters for +.BR selinux_restorecon (3) +by calling +.BR selabel_open (3) +with the +.B SELABEL_OPT_DIGEST +option only. This will enable a digest to be calculated on the currently +loaded policy +.BR file_contexts (5) +set of files as described in the +.B NOTES +section of +.BR selinux_restorecon (3). +.sp +Calling +.BR selinux_restorecon_default_handle () +is optional, however if used then +.BR selinux_restorecon_set_sehandle (3) +should be called with the returned handle to set this for use by +.BR selinux_restorecon (3). +.sp +.BR selinux_restorecon_default_handle () +is optional as +.BR selinux_restorecon (3) +will automatically call this and +.BR selinux_restorecon_set_sehandle (3) +provided a handle has not already been set, for +example by +.BR selinux_restorecon_set_sehandle (3) +to set customised +.BR selabel_open (3) +parameters. +. +.SH "RETURN VALUE" +A non\-NULL handle value is returned on success. On error, NULL is returned and +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_set_alt_rootpath (3), +.br +.BR selinux_restorecon_xattr (3) diff --git a/man/man3/selinux_restorecon_set_alt_rootpath.3 b/man/man3/selinux_restorecon_set_alt_rootpath.3 new file mode 100644 index 0000000..13a804a --- /dev/null +++ b/man/man3/selinux_restorecon_set_alt_rootpath.3 @@ -0,0 +1,37 @@ +.TH "selinux_restorecon_set_alt_rootpath" "3" "29 May 2016" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_set_alt_rootpath \- set an alternate rootpath. +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_restorecon_set_alt_rootpath(const char *" alt_rootpath ");" +.in +\w'void selinux_restorecon_set_alt_rootpath('u +. +.SH "DESCRIPTION" +.BR selinux_restorecon_set_alt_rootpath () +passes to +.BR selinux_restorecon (3) +a pointer containing an alternate rootpath +.IR alt_rootpath . +.sp +.BR selinux_restorecon_set_alt_rootpath () +must be called prior to +.BR selinux_restorecon (3). +. +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_xattr (3) diff --git a/man/man3/selinux_restorecon_set_exclude_list.3 b/man/man3/selinux_restorecon_set_exclude_list.3 new file mode 100644 index 0000000..373deec --- /dev/null +++ b/man/man3/selinux_restorecon_set_exclude_list.3 @@ -0,0 +1,35 @@ +.TH "selinux_restorecon_set_exclude_list" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_set_exclude_list \- set list of directories to be +excluded from relabeling. +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "void selinux_restorecon_set_exclude_list(const char **" exclude_list ");" +.in +\w'void selinux_restorecon_set_exclude_list('u +. +.SH "DESCRIPTION" +.BR selinux_restorecon_set_exclude_list () +passes to +.BR selinux_restorecon (3) +a pointer containing a +.B NULL +terminated list of one or more directories that are not to be relabeled in +.IR exclude_list . +.sp +.BR selinux_restorecon_set_exclude_list () +must be called prior to +.BR selinux_restorecon (3). +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_alt_rootpath (3), +.br +.BR selinux_restorecon_xattr (3) diff --git a/man/man3/selinux_restorecon_set_sehandle.3 b/man/man3/selinux_restorecon_set_sehandle.3 new file mode 100644 index 0000000..978945e --- /dev/null +++ b/man/man3/selinux_restorecon_set_sehandle.3 @@ -0,0 +1,38 @@ +.TH "selinux_restorecon_set_sehandle" "3" "20 Oct 2015" "Security Enhanced Linux" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_set_sehandle \- set a labeling handle for use by +.BR selinux_restorecon (3) +. +.SH "SYNOPSIS" +.B #include +.br +.B #include +.sp +.BI "void selinux_restorecon_set_sehandle(struct selabel_handle *" handle ");" +.in +\w'void selinux_restorecon_set_sehandle('u +. +.SH "DESCRIPTION" +.BR selinux_restorecon_set_sehandle () +sets the +.I handle +to be use by +.BR selinux_restorecon (3) +when relabeling files. +.sp +.BR selinux_restorecon_set_sehandle () +is generally used when customised +.BR selabel_open (3) +parameters are required to perform relabeling operations with +.BR selinux_restorecon (3). +. +.SH "SEE ALSO" +.BR selinux_restorecon (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_alt_rootpath (3), +.br +.BR selinux_restorecon_xattr (3) diff --git a/man/man3/selinux_restorecon_xattr.3 b/man/man3/selinux_restorecon_xattr.3 new file mode 100644 index 0000000..516d266 --- /dev/null +++ b/man/man3/selinux_restorecon_xattr.3 @@ -0,0 +1,169 @@ +.TH "selinux_restorecon_xattr" "3" "30 July 2016" "" "SELinux API documentation" + +.SH "NAME" +selinux_restorecon_xattr \- manage default +.I security.restorecon_last +extended attribute entries added by +.BR selinux_restorecon (3), +.BR setfiles (8) +or +.BR restorecon (8). + +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_restorecon_xattr(const char *" pathname , +.in +\w'int selinux_restorecon('u +.br +.BI "unsigned int " xattr_flags , +.br +.BI "struct dir_xattr ***" xattr_list ");" +.in +. +.SH "DESCRIPTION" +.BR selinux_restorecon_xattr () +returns a linked list of +.B dir_xattr +structures containing information described below based on: +.sp +.RS +.IR pathname +containing a directory tree to be searched for +.I security.restorecon_last +extended attribute entries. +.sp +.IR xattr_flags +contains options as follows: +.sp +.RS +.sp +.B SELINUX_RESTORECON_XATTR_RECURSE +recursively descend directories. +.sp +.B SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS +delete non-matching digests from each directory in +.IR pathname . +.sp +.B SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS +delete all digests from each directory in +.IR pathname . +.sp +.B SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS +do not read +.B /proc/mounts +to obtain a list of non-seclabel mounts to be excluded from the search. +.br +Setting +.B SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS +is useful where there is a non-seclabel fs mounted with a seclabel fs mounted +on a directory below this. +.RE +.sp +.I xattr_list +is the returned pointer to a linked list of +.B dir_xattr +structures, each containing the following information: +.sp +.RS +.ta 4n 16n 24n +.nf +struct dir_xattr { + char *directory; + char *digest; /* Printable hex encoded string */ + enum digest_result result; + struct dir_xattr *next; +}; +.fi +.ta +.RE +.sp +The +.B result +entry is enumerated as follows: +.RS +.ta 4n 16n 24n +.nf +enum digest_result { + MATCH = 0, + NOMATCH, + DELETED_MATCH, + DELETED_NOMATCH, + ERROR +}; +.fi +.ta +.RE +.sp +.I xattr_list +must be set to +.B NULL +before calling +.BR selinux_restorecon_xattr (3). +The caller is responsible for freeing the returned +.I xattr_list +entries in the linked list. +.RE +.sp +See the +.B NOTES +section for more information. + +.SH "RETURN VALUE" +On success, zero is returned. On error, \-1 is returned and +.I errno +is set appropriately. + +.SH "NOTES" +.IP "1." 4 +By default +.BR selinux_restorecon_xattr (3) +will use the default set of specfiles described in +.BR files_contexts (5) +to calculate the initial SHA1 digest to be used for comparison. +To change this default behavior +.BR selabel_open (3) +must be called specifying the required +.B SELABEL_OPT_PATH +and setting the +.B SELABEL_OPT_DIGEST +option to a non-NULL value. +.BR selinux_restorecon_set_sehandle (3) +is then called to set the handle to be used by +.BR selinux_restorecon_xattr (3). +.IP "2." 4 +By default +.BR selinux_restorecon_xattr (3) +reads +.B /proc/mounts +to obtain a list of non-seclabel mounts to be excluded from searches unless the +.B SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS +flag has been set. +.IP "3." 4 +.B RAMFS +and +.B TMPFS +filesystems do not support the +.IR security.restorecon_last +extended attribute and are automatically excluded from searches. +.IP "4." 4 +By default +.B stderr +is used to log output messages and errors. This may be changed by calling +.BR selinux_set_callback (3) +with the +.B SELINUX_CB_LOG +.I type +option. + +.SH "SEE ALSO" +.BR selinux_restorecon (3) +.br +.BR selinux_restorecon_set_sehandle (3), +.br +.BR selinux_restorecon_default_handle (3), +.br +.BR selinux_restorecon_set_exclude_list (3), +.br +.BR selinux_restorecon_set_alt_rootpath (3), +.br +.BR selinux_set_callback (3) diff --git a/man/man3/selinux_securetty_types_path.3 b/man/man3/selinux_securetty_types_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_securetty_types_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_set_callback.3 b/man/man3/selinux_set_callback.3 new file mode 100644 index 0000000..a4c613a --- /dev/null +++ b/man/man3/selinux_set_callback.3 @@ -0,0 +1,118 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selinux_set_callback" "3" "20 Jun 2007" "" "SELinux API documentation" +.SH "NAME" +selinux_set_callback \- userspace SELinux callback facilities +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "void selinux_set_callback(int " type ", union selinux_callback " callback ");" +. +.SH "DESCRIPTION" +.BR selinux_set_callback () +sets the callback indicated by +.I type +to the value of +.IR callback , +which should be passed as a function pointer cast to type +.B union +.BR selinux_callback . + +All callback functions should return a negative value with +.I errno +set appropriately on error. + +The available values for +.I type +are: +.TP +.B SELINUX_CB_LOG +.BI "int (*" func_log ") (int " type ", const char *" fmt ", ...);" + +This callback is used for logging and should process the +.BR printf (3) +style +.I fmt +string and arguments as appropriate. The +.I type +argument indicates the type of message and will be set to one of the following: + +.B SELINUX_ERROR + +.B SELINUX_WARNING + +.B SELINUX_INFO + +.B SELINUX_AVC +. +.TP +.B SELINUX_CB_AUDIT +.BI "int (*" func_audit ") (void *" auditdata ", security_class_t " cls , +.in +\w'int (*func_audit) ('u +.BI "char *" msgbuf ", size_t " msgbufsize ");" +.in + +This callback is used for supplemental auditing in AVC messages. The +.I auditdata +and +.I cls +arguments are the values passed to +.BR avc_has_perm (3). +A human-readable interpretation should be printed to +.I msgbuf +using no more than +.I msgbufsize +characters. +. +.TP +.B SELINUX_CB_VALIDATE +.BI "int (*" func_validate ") (char **" ctx ");" + +This callback is used for context validation. The callback may optionally modify the input context by setting the target of the +.I ctx +pointer to a new context. In this case, the old value should be freed with +.BR freecon (3). +The value of +.I errno +should be set to +.B EINVAL +to indicate an invalid context. +. +.TP +.B SELINUX_CB_SETENFORCE +.BI "int (*" func_setenforce ") (int " enforcing ");" + +This callback is invoked when the system enforcing state changes. +The +.I enforcing +argument indicates the new value and is set to +.I 1 +for enforcing mode, and +.I 0 +for permissive mode. +. +.TP +.B SELINUX_CB_POLICYLOAD +.BI "int (*" func_policyload ") (int " seqno ");" + +This callback is invoked when the system security policy is reloaded. +The +.I seqno +argument is the current sequential number of the policy generation in the system. +. +.SH "RETURN VALUE" +None. +. +.SH "ERRORS" +None. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR selabel_open (3), +.BR avc_init (3), +.BR avc_netlink_open (3), +.BR selinux (8) diff --git a/man/man3/selinux_set_mapping.3 b/man/man3/selinux_set_mapping.3 new file mode 100644 index 0000000..a93f7b2 --- /dev/null +++ b/man/man3/selinux_set_mapping.3 @@ -0,0 +1,88 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2008 +.TH "selinux_set_mapping" "3" "12 Jun 2008" "" "SELinux API documentation" +.SH "NAME" +selinux_set_mapping \- establish dynamic object class and permission mapping +. +.SH "SYNOPSIS" +.B #include +.sp +.nf +struct security_class_mapping { + const char *name; + const char *perms[]; +}; +.fi +.sp +.BI "int selinux_set_mapping(struct security_class_mapping *" map ");" +. +.SH "DESCRIPTION" +.BR selinux_set_mapping () +establishes a mapping from a user-provided ordering of object classes and permissions to the numbers actually used by the loaded system policy. Use of this function is highly preferred over the generated constants in the libselinux header files, as this method allows the policy's class and permission values to change over time. + +After the mapping is established, all libselinux functions that operate on class and permission values take the user-provided numbers, which are determined as follows: + +The +.I map +argument consists of an array of +.B security_class_mapping +structures, which must be terminated by a structure having a NULL name field. Except for this last structure, the +.I name +field should refer to the string name of an object class, and the corresponding +.I perms +field should refer to an array of permission bit names terminated by a NULL string. + +The object classes named in the mapping and the bit indexes of each set of permission bits named in the mapping are numbered in order starting from 1. These numbers are the values that should be passed to subsequent libselinux calls. +. +.SH "RETURN VALUE" +Zero is returned on success. On error, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +.TP +.B EINVAL +One of the class or permission names requested in the mapping is not present in the loaded policy. +.TP +.B ENOMEM +An attempt to allocate memory failed. +. +.SH "EXAMPLE" +.RS +.ta 4n 10n +.nf +struct security_class_mapping map[] = { + { "file", { "create", "unlink", "read", "write", NULL } }, + { "socket", { "bind", NULL } }, + { "process", { "signal", NULL } }, + { NULL } +}; + +if (selinux_set_mapping(map) < 0) + exit(1); +.fi +.ta +.RE + +In this example, after the call has succeeded, classes +.BR file , +.BR socket , +and +.B process +will be identified by 1, 2 and 3, respectively. Permissions +.IR create , +.IR unlink , +.IR read , +and +.I write +(for the +.B file +class) will be identified by 1, 2, 4, and 8 respectively. Classes and permissions not listed in the mapping cannot be used. +. +.SH "AUTHOR" +Eamon Walsh +. +.SH "SEE ALSO" +.BR avc_open (8), +.BR selinux (8) diff --git a/man/man3/selinux_set_policy_root.3 b/man/man3/selinux_set_policy_root.3 new file mode 100644 index 0000000..8077658 --- /dev/null +++ b/man/man3/selinux_set_policy_root.3 @@ -0,0 +1 @@ +.so man3/selinux_policy_root.3 diff --git a/man/man3/selinux_status_close.3 b/man/man3/selinux_status_close.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/man/man3/selinux_status_close.3 @@ -0,0 +1 @@ +.so man3/selinux_status_open.3 diff --git a/man/man3/selinux_status_deny_unknown.3 b/man/man3/selinux_status_deny_unknown.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/man/man3/selinux_status_deny_unknown.3 @@ -0,0 +1 @@ +.so man3/selinux_status_open.3 diff --git a/man/man3/selinux_status_getenforce.3 b/man/man3/selinux_status_getenforce.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/man/man3/selinux_status_getenforce.3 @@ -0,0 +1 @@ +.so man3/selinux_status_open.3 diff --git a/man/man3/selinux_status_open.3 b/man/man3/selinux_status_open.3 new file mode 100644 index 0000000..2d44be5 --- /dev/null +++ b/man/man3/selinux_status_open.3 @@ -0,0 +1,100 @@ +.TH "selinux_status_open" "3" "22 January 2011" "kaigai@ak.jp.nec.com" "SELinux API documentation" +.SH "NAME" +selinux_status_open, selinux_status_close, selinux_status_updated, +selinux_status_getenforce, selinux_status_policyload and +selinux_status_deny_unknown \- reference the SELinux kernel status +without invocation of system calls +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_status_open(int " fallback ");" +.sp +.BI "void selinux_status_close(void);" +.sp +.BI "int selinux_status_updated(void);" +.sp +.BI "int selinux_status_getenforce(void);" +.sp +.BI "int selinux_status_policyload(void);" +.sp +.BI "int selinux_status_deny_unknown(void);" +. +.SH "DESCRIPTION" +Linux 2.6.37 or later provides a SELinux kernel status page; being mostly +placed on +.I /sys/fs/selinux/status +entry. It enables userspace applications to mmap this page with read-only +mode, then it informs some status without system call invocations. +.sp +In some cases that a userspace application tries to apply heavy frequent +access control; such as row-level security in databases, it will face +unignorable cost to communicate with kernel space to check invalidation +of userspace avc. +.sp +These functions provides applications a way to know some kernel events +without system-call invocation or worker thread for monitoring. +.sp +.BR selinux_status_open () +tries to +.BR open (2) +.I /sys/fs/selinux/status +and +.BR mmap (2) +it in read-only mode. The file-descriptor and pointer to the page shall +be stored internally; Don't touch them directly. +Set 1 on the +.I fallback +argument to handle a case of older kernels without kernel status page support. +In this case, this function tries to open a netlink socket using +.BR avc_netlink_open (3) +and overwrite corresponding callbacks ( setenforce and policyload). +Thus, we need to pay attention to the interaction with these interfaces, +when fallback mode is enabled. +.sp +.BR selinux_status_close () +unmap the kernel status page and close its file descriptor, or close the +netlink socket if fallbacked. +.sp +.BR selinux_status_updated () +informs us whether something has been updated since the last call. +It returns 0 if nothing was happened, however, 1 if something has been +updated in this duration, or \-1 on error. +.sp +.BR selinux_status_getenforce () +returns 0 if SELinux is running in permissive mode, 1 if enforcing mode, +or \-1 on error. +Same as +.BR security_getenforce (3) +except with or without system call invocation. +.sp +.BR selinux_status_policyload () +returns times of policy reloaded on the running system, or \-1 on error. +Note that it is not a reliable value on fallback-mode until it receive +the first event message via netlink socket. +Thus, don't use this value to know actual times of policy reloaded. +.sp +.BR selinux_status_deny_unknown () +returns 0 if SELinux treats policy queries on undefined object classes or +permissions as being allowed, 1 if such queries are denied, or \-1 on error. +.sp +Also note that these interfaces are not thread-safe, so you have to protect +them from concurrent calls using exclusive locks when multiple threads are +performing. +. +.SH "RETURN VALUE" +.BR selinux_status_open () +returns 0 or 1 on success. 1 means we are ready to use these interfaces, +but netlink socket was opened as fallback instead of the kernel status page. +On error, \-1 shall be returned. +.sp +Any other functions with a return value shall return its characteristic +value as described above, or \-1 on errors. +. +.SH "SEE ALSO" +.ad l +.nh +.BR mmap (2), +.BR avc_netlink_open (3), +.BR security_getenforce (3), +.BR security_deny_unknown (3) diff --git a/man/man3/selinux_status_policyload.3 b/man/man3/selinux_status_policyload.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/man/man3/selinux_status_policyload.3 @@ -0,0 +1 @@ +.so man3/selinux_status_open.3 diff --git a/man/man3/selinux_status_updated.3 b/man/man3/selinux_status_updated.3 new file mode 100644 index 0000000..52a4169 --- /dev/null +++ b/man/man3/selinux_status_updated.3 @@ -0,0 +1 @@ +.so man3/selinux_status_open.3 diff --git a/man/man3/selinux_user_contexts_path.3 b/man/man3/selinux_user_contexts_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_user_contexts_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_usersconf_path.3 b/man/man3/selinux_usersconf_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_usersconf_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/selinux_x_context_path.3 b/man/man3/selinux_x_context_path.3 new file mode 100644 index 0000000..175a611 --- /dev/null +++ b/man/man3/selinux_x_context_path.3 @@ -0,0 +1 @@ +.so man3/selinux_binary_policy_path.3 diff --git a/man/man3/set_matchpathcon_flags.3 b/man/man3/set_matchpathcon_flags.3 new file mode 100644 index 0000000..2841bec --- /dev/null +++ b/man/man3/set_matchpathcon_flags.3 @@ -0,0 +1,62 @@ +.TH "set_matchpathcon_flags" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.SH "NAME" +set_matchpathcon_flags, set_matchpathcon_invalidcon, set_matchpathcon_printf \- set flags controlling the operation of matchpathcon or matchpathcon_index and configure the behaviour of validity checking and error displaying +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "void set_matchpathcon_flags(unsigned int " flags ");" +.sp +.BI "void set_matchpathcon_invalidcon(int (*" f ")(const char *" path ", unsigned " lineno ", char *" context "));" +.sp +.BI "void set_matchpathcon_printf(void (*" f ")(const char *" fmt ", ...));" +. +.SH "DESCRIPTION" +.BR set_matchpathcon_flags () +sets the flags controlling the operation of +.BR matchpathcon_init (3) +and subsequently +.BR matchpathcon_index (3) +or +.BR matchpathcon (3). +If the +.B MATCHPATHCON_BASEONLY +flag is set, then only the base file contexts configuration file +will be processed, not any dynamically generated entries or local customizations. +.sp + +.BR set_matchpathcon_invalidcon () +sets the function used by +.BR matchpathcon_init (3) +when checking the validity of a context in the file contexts +configuration. If not set, then this defaults to a test based +on +.BR security_check_context (3), +which checks validity against the active policy on a SELinux system. +This can be set to instead perform checking based on a binary policy file, +e.g. using +.BR sepol_check_context (3), +as is done by +.B setfiles \-c. +The function is also responsible for reporting any such error, and +may include the +.I path +and +.I lineno +in such error messages. +.sp + +.BR set_matchpathcon_printf () +sets the function used by +.BR matchpathcon_init (3) +when displaying errors about the file contexts configuration. If not set, +then this defaults to fprintf(stderr, fmt, ...). This can be set to redirect +error reporting to a different destination. +. +.SH "RETURN VALUE" +Returns zero on success or \-1 otherwise. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " matchpathcon "(3), " matchpathcon_index "(3), " set_matchpathcon_invalidcon "(3), " set_matchpathcon_printf "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/set_matchpathcon_invalidcon.3 b/man/man3/set_matchpathcon_invalidcon.3 new file mode 100644 index 0000000..b861e1c --- /dev/null +++ b/man/man3/set_matchpathcon_invalidcon.3 @@ -0,0 +1 @@ +.so man3/set_matchpathcon_flags.3 diff --git a/man/man3/set_matchpathcon_printf.3 b/man/man3/set_matchpathcon_printf.3 new file mode 100644 index 0000000..b861e1c --- /dev/null +++ b/man/man3/set_matchpathcon_printf.3 @@ -0,0 +1 @@ +.so man3/set_matchpathcon_flags.3 diff --git a/man/man3/set_selinuxmnt.3 b/man/man3/set_selinuxmnt.3 new file mode 100644 index 0000000..d7805c9 --- /dev/null +++ b/man/man3/set_selinuxmnt.3 @@ -0,0 +1 @@ +.so man3/init_selinuxmnt.3 diff --git a/man/man3/setcon.3 b/man/man3/setcon.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/setcon.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/setcon_raw.3 b/man/man3/setcon_raw.3 new file mode 100644 index 0000000..1210b5a --- /dev/null +++ b/man/man3/setcon_raw.3 @@ -0,0 +1 @@ +.so man3/getcon.3 diff --git a/man/man3/setexeccon.3 b/man/man3/setexeccon.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/man/man3/setexeccon.3 @@ -0,0 +1 @@ +.so man3/getexeccon.3 diff --git a/man/man3/setexeccon_raw.3 b/man/man3/setexeccon_raw.3 new file mode 100644 index 0000000..b2e6ab8 --- /dev/null +++ b/man/man3/setexeccon_raw.3 @@ -0,0 +1 @@ +.so man3/getexeccon.3 diff --git a/man/man3/setfilecon.3 b/man/man3/setfilecon.3 new file mode 100644 index 0000000..0e9a383 --- /dev/null +++ b/man/man3/setfilecon.3 @@ -0,0 +1,66 @@ +.TH "setfilecon" "3" "1 January 2004" "russell@coker.com.au" "SELinux API documentation" +.SH "NAME" +setfilecon, fsetfilecon, lsetfilecon \- set SELinux security context of a file +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int setfilecon(const char *" path ", char *" con ); +.sp +.BI "int setfilecon_raw(const char *" path ", char *" con ); +.sp +.BI "int lsetfilecon(const char *" path ", char *" con ); +.sp +.BI "int lsetfilecon_raw(const char *" path ", char *" con ); +.sp +.BI "int fsetfilecon(int "fd ", char *" con ); +.sp +.BI "int fsetfilecon_raw(int "fd ", char *" con ); +. +.SH "DESCRIPTION" +.BR setfilecon () +sets the security context of the file system object. + +.BR lsetfilecon () +is identical to setfilecon, except in the case of a symbolic link, where the +link itself has it's context set, not the file that it refers to. + +.BR fsetfilecon () +is identical to setfilecon, only the open file pointed to by filedes (as +returned by +.BR open (2)) +has it's context set in place of path. + +.BR setfilecon_raw (), +.BR lsetfilecon_raw (), +and +.BR fsetfilecon_raw () +behave identically to their non-raw counterparts but do not perform context +translation. +. +.SH "RETURN VALUE" +On success, zero is returned. On failure, \-1 is returned and +.I errno +is set appropriately. +. +.SH "ERRORS" +If there is insufficient space remaining to store the extended +attribute, +.I errno +is set to either +.BR ENOSPC , +or +.B EDQUOT +if quota enforcement was the cause. + +If extended attributes are not supported by the filesystem, or are disabled, +.I errno +is set to +.BR ENOTSUP . + +The errors documented for the +.BR stat (2) +system call are also applicable here. +. +.SH "SEE ALSO" +.BR selinux "(3), " freecon "(3), " getfilecon "(3), " setfscreatecon "(3)" diff --git a/man/man3/setfilecon_raw.3 b/man/man3/setfilecon_raw.3 new file mode 100644 index 0000000..33c321a --- /dev/null +++ b/man/man3/setfilecon_raw.3 @@ -0,0 +1 @@ +.so man3/setfilecon.3 diff --git a/man/man3/setfscreatecon.3 b/man/man3/setfscreatecon.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/man/man3/setfscreatecon.3 @@ -0,0 +1 @@ +.so man3/getfscreatecon.3 diff --git a/man/man3/setfscreatecon_raw.3 b/man/man3/setfscreatecon_raw.3 new file mode 100644 index 0000000..21aeebd --- /dev/null +++ b/man/man3/setfscreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getfscreatecon.3 diff --git a/man/man3/setkeycreatecon.3 b/man/man3/setkeycreatecon.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/man/man3/setkeycreatecon.3 @@ -0,0 +1 @@ +.so man3/getkeycreatecon.3 diff --git a/man/man3/setkeycreatecon_raw.3 b/man/man3/setkeycreatecon_raw.3 new file mode 100644 index 0000000..1e0ec5f --- /dev/null +++ b/man/man3/setkeycreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getkeycreatecon.3 diff --git a/man/man3/setsockcreatecon.3 b/man/man3/setsockcreatecon.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/man/man3/setsockcreatecon.3 @@ -0,0 +1 @@ +.so man3/getsockcreatecon.3 diff --git a/man/man3/setsockcreatecon_raw.3 b/man/man3/setsockcreatecon_raw.3 new file mode 100644 index 0000000..ed1a371 --- /dev/null +++ b/man/man3/setsockcreatecon_raw.3 @@ -0,0 +1 @@ +.so man3/getsockcreatecon.3 diff --git a/man/man3/sidget.3 b/man/man3/sidget.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/man/man3/sidget.3 @@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3 diff --git a/man/man3/sidput.3 b/man/man3/sidput.3 new file mode 100644 index 0000000..d7c3e66 --- /dev/null +++ b/man/man3/sidput.3 @@ -0,0 +1 @@ +.so man3/avc_context_to_sid.3 diff --git a/man/man3/string_to_av_perm.3 b/man/man3/string_to_av_perm.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/string_to_av_perm.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man3/string_to_security_class.3 b/man/man3/string_to_security_class.3 new file mode 100644 index 0000000..bda9daf --- /dev/null +++ b/man/man3/string_to_security_class.3 @@ -0,0 +1 @@ +.so man3/security_class_to_string.3 diff --git a/man/man5/booleans.5 b/man/man5/booleans.5 new file mode 100644 index 0000000..2e9caa7 --- /dev/null +++ b/man/man5/booleans.5 @@ -0,0 +1,80 @@ +.TH "booleans" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +booleans \- The SELinux booleans configuration files +. +.SH "DESCRIPTION" +The \fIbooleans\fR file, if present contains booleans to support a specific distribution. +.sp +The \fIbooleans.local\fR file, if present contains locally generated booleans. +.sp +Both files contain a list of boolean names and their associated values. +.sp +Generally the \fIbooleans\fR and/or \fIbooleans.local\fR files are not present (they have been deprecated). However if there is an SELinux-aware application that uses the libselinux functions listed below, then these files may be present: +.sp +.RS +.BR security_set_boolean_list "(3) " +.RS +Writes a \fIbooleans.local\fR file if flag \fIpermanent\fR = \fI1\fR. +.sp +.RE +.RE +.RS +.BR security_load_booleans "(3) " +.RS +Looks for a \fIbooleans\fR and/or \fIbooleans.local\fR file at \fBselinux_booleans_path\fR(3) unless a specific path is specified as a parameter. +.RE +.RE +.sp +\fBbooleans\fR(8) has details on booleans and \fBsetsebool\fR(8) describes how booleans can now be set persistent across reboots. +.sp +\fBselinux_booleans_path\fR(3) will return the active policy path to these files. The default boolean files are: +.RS +.I /etc/selinux/{SELINUXTYPE}/booleans +.br +.I /etc/selinux/{SELINUXTYPE}/booleans.local +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Both boolean files have the same format and contain one or more boolean names and their value. +.sp +The format is: +.RS +.I boolean_name +.I value +.sp +.RE +Where: +.RS +.I boolean_name +.RS +The name of the boolean. +.RE +.I value +.RS +The default setting for the boolean. This can be one of the following: +.RS +.IR true " | " false " | " 1 " | " 0 +.RE +.RE +.RE +.sp +Note that if +.B SETLOCALDEFS +is set in the SELinux +.I config +file (see +.BR selinux_config "(5)), then " selinux_mkload_policy "(3) will check for a " +.I booleans.local +file in the +.BR selinux_booleans_path (3) +and also a +.I local.users +file (see +.BR local.users "(5)) in the " selinux_users_path "(3). " +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " booleans "(8), " setsebool "(8), " semanage "(8), " selinux_booleans_path "(3), " security_set_boolean_list "(3), " security_load_booleans "(3), " selinux_mkload_policy "(3), " selinux_users_path "(3), " selinux_config "(5), " local.users "(5) " diff --git a/man/man5/customizable_types.5 b/man/man5/customizable_types.5 new file mode 100644 index 0000000..4924f7b --- /dev/null +++ b/man/man5/customizable_types.5 @@ -0,0 +1,59 @@ +.TH "customizable_types" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +customizable_types \- The SELinux customizable types configuration file +. +.SH "DESCRIPTION" +The \fIcustomizable_types\fR file contains a list of types that can be customised in some way by SELinux-aware applications. +.sp +Generally this is a file context type that is usually set on files that need to be shared among certain domains and where the administrator wants to manually manage the type. +.sp +The use of customizable types is deprecated as the preferred approach is to use +.BR semanage (8) +.BR fcontext (8) +.BR ... (8). +However, SELinux-aware applications such as +.BR setfiles (8) +will use this information to obtain a list of types relating to files that should not be relabeled. +.sp +.BR selinux_customizable_types_path (3) +will return the active policy path to this file. The default customizable types file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/customizable_types +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR is_context_customizable (3) +reads this file to determine if a context is customisable or not for the active policy. +. +.SH "FILE FORMAT" +Each line in the file consists of the following: +.RS +.I type +.RE +.sp +Where: +.RS +.I type +.RS +The type defined in the policy that can be customised. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/customizable_types +.br +mount_loopback_t +.br +public_content_rw_t +.br +public_content_t +.br +swapfile_t +.br +sysadm_untrusted_content_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_customizable_types_path "(3), " is_context_customizable "(3), " semanage "(8), " setfiles "(8), " selinux_config "(5) " diff --git a/man/man5/default_contexts.5 b/man/man5/default_contexts.5 new file mode 100644 index 0000000..f63d24a --- /dev/null +++ b/man/man5/default_contexts.5 @@ -0,0 +1,71 @@ +.TH "default_contexts" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +default_contexts \- The SELinux default contexts configuration file +. +.SH "DESCRIPTION" +The default contexts configuration file \fIdefault_contexts\fR contains entries that allow SELinux-aware login applications such as +.BR PAM "(8) " +.sp +SELinux-aware login applications generally use one or more of the following libselinux functions that read these files from the active policy path: +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +.sp +The default context configuration file path for the active policy is returned by \fBselinux_default_contexts_path\fR(3). The default, default contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the default configuration file consists of the following: +.RS +.I login_process user_login_process [user_login_process] ... +.RE +.sp +Where: +.RS +.I login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the login process context that are defined in the policy. +.RE +.I user_login_process +.RS +This consists of one or more \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entries that represent the user login process context defined in the policy. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/default_contexts +.br +system_r:crond_t:s0 system_r:system_crond_t:s0 +.br +system_r:local_login_t:s0 user_r:user_t:s0 staff_r:staff_t:s0 +.br +system_r:remote_login_t:s0 user_r:user_t:s0 +.br +system_r:sshd_t:s0 user_r:user_t:s0 +.br +system_r:sulogin_t:s0 sysadm_r:sysadm_t:s0 +.br +system_r:xdm_t:s0 user_r:user_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_default_contexts_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " diff --git a/man/man5/default_type.5 b/man/man5/default_type.5 new file mode 100644 index 0000000..082a5f0 --- /dev/null +++ b/man/man5/default_type.5 @@ -0,0 +1,39 @@ +.TH "default_type" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +default_type \- The SELinux default type configuration file +. +.SH "DESCRIPTION" +The \fIdefault_type\fR file contains entries that allow SELinux-aware applications such as \fBnewrole\fR(1) to select a default type for a role if one is not supplied. +.sp +\fBselinux_default_type_path\fR(3) will return the active policy path to this file. The default, default type file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_type +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +\fBget_default_type\fR(3) reads this file to determine a type for the active policy. +. +.SH "FILE FORMAT" +Each line within the \fIdefault_type\fR file is formatted with \fIrole\fB:\fItype\fR entries where: +.RS +.I role +.RS +The SELinux role. +.RE +.I type +.RS +The domain type that is returned for this role. +.RE +. +.SH "EXAMPLE" +# ./contexts/default_type +.br +auditadm_r:auditadm_t +.br +user_r:user_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " get_default_type "(3), " newrole "(1), " selinux_default_type_path "(3), " selinux_config "(5) " diff --git a/man/man5/failsafe_context.5 b/man/man5/failsafe_context.5 new file mode 100644 index 0000000..e7032e5 --- /dev/null +++ b/man/man5/failsafe_context.5 @@ -0,0 +1,64 @@ +.TH "failsafe_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +failsafe_context \- The SELinux fail safe context configuration file +. +.SH "DESCRIPTION" +The +.I failsafe_context +file allows SELinux-aware applications such as +.BR PAM "(8) " +to obtain a known valid login context for an administrator if no valid default entries can be found elsewhere. +.sp +.BR selinux_failsafe_context_path "(3) " +will return the active policy path to this file. The default failsafe context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/failsafe_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The following functions read this file from the active policy path if they cannot obtain a default context: +.br +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +. +.SH "FILE FORMAT" +The file consists of a single line entry as follows: +.RS +\fIrole\fB:\fItype\fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I role +.I type +.I range +.RS +A role, type and optional range (for MCS/MLS), separated by colons (:) to form a valid login process context for an administrator to access the system. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/failsafe_context +.br +unconfined_r:unconfined_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_failsafe_context_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " diff --git a/man/man5/file_contexts.5 b/man/man5/file_contexts.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/man5/file_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/man5/file_contexts.homedirs.5 b/man/man5/file_contexts.homedirs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/man5/file_contexts.homedirs.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/man5/file_contexts.local.5 b/man/man5/file_contexts.local.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/man5/file_contexts.local.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/man5/file_contexts.subs.5 b/man/man5/file_contexts.subs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/man5/file_contexts.subs.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/man5/file_contexts.subs_dist.5 b/man/man5/file_contexts.subs_dist.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/man5/file_contexts.subs_dist.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/man5/local.users.5 b/man/man5/local.users.5 new file mode 100644 index 0000000..94d4673 --- /dev/null +++ b/man/man5/local.users.5 @@ -0,0 +1,68 @@ +.TH "local.users" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +local.users \- The SELinux local users configuration file +. +.SH "DESCRIPTION" +The file contains local user definitions in the form of policy language user statements and is only found on older SELinux systems as it has been deprecated and replaced by the \fBsemange\fR(8) services. +.sp +This file is only read by \fBselinux_mkload_policy\fR(3) when \fBSETLOCALDEFS\fR in the SELinux \fIconfig\fR file (see \fBselinux_config\fR(5)) is set to \fI1\fR. +.sp +.BR selinux_users_path "(3) " +will return the active policy path to the directory where this file is located. The default local users file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/local.users +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +The file consists of one or more entries terminated with '\fB;\fR', each on a separate line as follows: +.RS +\fBuser \fIseuser_id \fBroles \fIrole_id\fR [[\fBlevel \fIlevel\fR] [\fBrange \fIrange\fR]]\fB;\fR +.RE +.sp +Where: +.RS +.B user +.RS +The user keyword. +.RE +.I seuser_id +.RS +The SELinux user identifier. +.RE +.B roles +.RS +The roles keyword. +.RE +.I role_id +.RS +One or more previously declared role identifiers. Multiple role identifiers consist of a space separated list enclosed in braces '{}'. +.RE +.B level +.RS +If MLS/MCS is configured, the level keyword. +.RE +.I level +.RS +The users default security level. Note that only the sensitivity component of the level (e.g. s0) is required. +.RE +.B range +.RS +If MLS/MCS is configured, the range keyword. +.RE +.I range +.RS +The current and clearance levels that the user can run. These are separated by a hyphen '\fB-\fR' as shown in the \fBEXAMPLE\fR section. +.RE +.RE +. +.SH "EXAMPLE" +# ./users/local.users +.br +user test_u roles staff_r level s0 range s0 \- s15:c0.c1023; +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " semanage "(8), " selinux_users_path "(3), " selinux_config "(5), " selinux_mkload_policy "(3) " diff --git a/man/man5/media.5 b/man/man5/media.5 new file mode 100644 index 0000000..14f00f2 --- /dev/null +++ b/man/man5/media.5 @@ -0,0 +1 @@ +.so man5/selabel_media.5 diff --git a/man/man5/removable_context.5 b/man/man5/removable_context.5 new file mode 100644 index 0000000..f16e8bd --- /dev/null +++ b/man/man5/removable_context.5 @@ -0,0 +1,36 @@ +.TH "removable_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +removable_context \- The SELinux removable devices context configuration file +. +.SH "DESCRIPTION" +This file contains the default label that should be used for removable devices. +.sp +.BR selinux_removable_context_path "(3) " +will return the active policy path to this file. The default removable context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/removable_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +The file consists of a single line entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that will be applied to removable devices. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/removable_contexts +.br +system_u:object_r:removable_t:s0 +. +.SH "SEE ALSO" +.BR selinux "(8), " selinux_removable_context_path "(3), " selinux_config "(5) " diff --git a/man/man5/secolor.conf.5 b/man/man5/secolor.conf.5 new file mode 100644 index 0000000..a3bf2da --- /dev/null +++ b/man/man5/secolor.conf.5 @@ -0,0 +1,178 @@ +.TH "secolor.conf" "5" "08 April 2011" "SELinux API documentation" +.SH "NAME" +secolor.conf \- The SELinux color configuration file +. +.SH "DESCRIPTION" +This optional file controls the color to be associated to the context components associated to the +.I raw +context passed by +.BR selinux_raw_context_to_color "(3)," +when context related information is to be displayed in color by an SELinux-aware application. +.sp +.BR selinux_raw_context_to_color "(3)" +obtains this color information from the active policy +.B secolor.conf +file as returned by +.BR selinux_colors_path "(3)." +. +.SH "FILE FORMAT" +The file format is as follows: +.RS +.B color +.I color_name +.BI "= #"color_mask +.br +[...] +.sp +.I context_component string +.B = +.I fg_color_name bg_color_name +.br +[...] +.sp +.RE + +Where: +.br +.B color +.RS +The color keyword. Each color entry is on a new line. +.RE +.I color_name +.RS +A single word name for the color (e.g. red). +.RE +.I color_mask +.RS +A color mask starting with a hash (#) that describes the hexadecimal RGB colors with black being #000000 and white being #ffffff. +.RE +.I context_component +.RS +The context component name that must be one of the following: +.br +.RS +user, role, type or range +.RE +Each +.IR context_component " " string " ..." +entry is on a new line. +.RE +.I string +.RS +This is the +.I context_component +string that will be matched with the +.I raw +context component passed by +.BR selinux_raw_context_to_color "(3)." +.br +A wildcard '*' may be used to match any undefined string for the user, role and type +.I context_component +entries only. +.RE + +.I fg_color_name +.RS +The color_name string that will be used as the foreground color. +A +.I color_mask +may also be used. +.RE +.I bg_color_name +.RS +The color_name string that will be used as the background color. +A +.I color_mask +may also be used. +.RE +. +.SH "EXAMPLES" +Example 1 entries are: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #D2B48C +.sp +user * = black white +.br +role * = white black +.br +type * = tan orange +.br +range s0\-s0:c0.c1023 = black green +.br +range s1\-s1:c0.c1023 = white green +.br +range s3\-s3:c0.c1023 = black tan +.br +range s5\-s5:c0.c1023 = white blue +.br +range s7\-s7:c0.c1023 = black red +.br +range s9\-s9:c0.c1023 = black orange +.br +range s15\-s15:c0.c1023 = black yellow +.RE + +.sp +Example 2 entries are: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #d2b48c +.sp +user unconfined_u = #ff0000 green +.br +role unconfined_r = red #ffffff +.br +type unconfined_t = red orange +.br +user user_u = black green +.br +role user_r = white black +.br +type user_t = tan red +.br +user xguest_u = black yellow +.br +role xguest_r = black red +.br +type xguest_t = black green +.br +user sysadm_u = white black +.br +range s0-s0:c0.c1023 = black white +.br +user * = black white +.br +role * = black white +.br +type * = black white +.RE +. +.SH "SEE ALSO" +.BR selinux "(8), " selinux_raw_context_to_color "(3), " selinux_colors_path "(3)" diff --git a/man/man5/securetty_types.5 b/man/man5/securetty_types.5 new file mode 100644 index 0000000..dbc5c2e --- /dev/null +++ b/man/man5/securetty_types.5 @@ -0,0 +1,45 @@ +.TH "securetty_types" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +securetty_types \- The SELinux secure tty type configuration file +. +.SH "DESCRIPTION" +The +.I securetty_types +file contains a list of types associated to secure tty type that are defined in the policy for use by SELinux-aware applications. +.sp +.BR selinux_securetty_types_path "(3) " +will return the active policy path to this file. The default securetty types file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/securetty_types +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR selinux_check_securetty_context "(3) reads this file to determine if a context is for a secure tty defined in the active policy. " +.sp +SELinux-aware applications such as +.BR newrole "(1) use this information to check the status of a tty. " +. +.SH "FILE FORMAT" +Each line in the file consists of the following entry: +.sp +.RS +.I type +.RS +One or more type entries that are defined in the policy for secure tty devices. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/securetty_types +.br +sysadm_tty_device_t +.br +user_tty_device_t +.br +staff_tty_device_t +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_securetty_types_path "(3), " newrole "(1), " selinux_check_securetty_context "(3), " selinux_config "(5) " diff --git a/man/man5/selabel_db.5 b/man/man5/selabel_db.5 new file mode 100644 index 0000000..76eb9bc --- /dev/null +++ b/man/man5/selabel_db.5 @@ -0,0 +1,219 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: KaiGai Kohei 2009 +.TH "selabel_db" "5" "01 DEC 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_db \- userspace SELinux labeling interface and configuration file format for the RDBMS objects context backend +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "DESCRIPTION" +The DB contexts backend maps from a pair of object name and class into security contexts. It is used to find the appropriate context for database objects when relabeling a certain database. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +The \fIobject_name\fR should be a fully qualified name using the hierarchy of database objects. For example, the \fBpg_class\fR table in the \fBpostgres\fR database and \fBpg_catalog\fR schema should be qualified as: +.RS +.B Bpostgres.pg_catalog.pg_class +.RE +.sp +The \fBNOTES\fR section has further information on database support for namespace hierarchies. +.sp +The \fIobject_type\fR argument should be set to one of the following values: +.RS +.TP +.B SELABEL_DB_DATABASE +The +.I object_name +argument specifies the name of a database itself, such as "postgres". +.TP +.B SELABEL_DB_SCHEMA +The +.I object_name +argument specifies the name of a schema object, such as "postgres.public". +.TP +.B SELABEL_DB_TABLE +The +.I object_name +argument specifies the name of a table object, such as "postgres.public.my_table" +.TP +.B SELABEL_DB_COLUMN +The +.I object_name +argument specifies the name of a column object, such as "postgres.public.my_table.user_id" +.TP +.B SELABEL_DB_TUPLE +The +.I object_name +argument specifies the name of a table object which contains the tuples to be relabeled, such as "postgresql.public.my_table". Note that we have no way to identify individual tuple objects, except for WHERE clause on DML statements, because it has no name. +.TP +.B SELABEL_DB_PROCEDURE +The +.I object_name +argument specifies the name of a procedure object, such as "postgres.public.my_func". Note that we don't support lookup of individual security contexts for procedures which have the same name but different arguments. +.TP +.B SELABEL_DB_SEQUENCE +The +.I object_name +argument specifies the name of a sequence object, such as "postgres.public.my_seq". +.TP +.B SELABEL_DB_BLOB +The +.I object_name +argument specifies the name of a large object, such as "postgres.16308". +Note that a large object does not have a name, so it is identified by its identifier value. +.TP +.B SELABEL_DB_VIEW +The +.I object_name +argument specifies the name of a view object, such as "postgres.public.my_view". +.TP +.B SELABEL_DB_LANGUAGE +The +.I object_name +argument specifies the name of a language object, such as "postgres.public.tcl". +.TP +.B SELABEL_DB_EXCEPTION +The +.I object_name +argument specifies the name of a exception object. +.TP +.B SELABEL_DB_DATATYPE +The +.I object_name +argument specifies the name of a type or domain object, such as postgres.public.my_type. +.RE +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the database object context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard DB contexts file. +It tries to open the specfile designed for SE-PostgreSQL as default, so if another RDBMS uses this interface, it needs to give an explicit specfile designed for that RDBMS (see the \fBFILES\fR section for details). +.RE +. +.SH "FILES" +The database context file used to retrieve a context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy database contexts location (as returned by \fBselinux_sepgsql_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used (this option must be used to support databases other than SE-PostgreSQL). +.sp +The default database object contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/sepgsql_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The entries within the database contexts file are shown in the \fBObject Name String Values\fR and \fBFILE FORMAT\fR sections. +. +.SH "Object Name String Values" +The string name assigned to each \fIobject_type\fR argument that can be present in the database contexts file are: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Text Name +SELABEL_DB_DATABASE@db_database +SELABEL_DB_SCHEMA@db_schema +SELABEL_DB_VIEW@db_view +SELABEL_DB_LANGUAGE@db_language +SELABEL_DB_TABLE@db_table +SELABEL_DB_COLUMN@db_column +SELABEL_DB_TUPLE@db_tuple +SELABEL_DB_PROCEDURE@db_procedure +SELABEL_DB_SEQUENCE@db_sequence +SELABEL_DB_BLOB@db_blob +SELABEL_DB_EXCEPTION@db_exception +SELABEL_DB_DATATYPE@db_datatype +.TE +. +.SH "FILE FORMAT" +Each line within the database contexts file is as follows: +.RS +.I object_type object_name context +.RE +.sp +Where: +.RS +.I object_type +.RS +This is the string representation of the object type shown in the \fBObject Name String Values\fR section. +.RE +.I object_name +.RS +The key used to obtain the context based on the \fIobject_type\fR. +.sp +The entry can contain '*' for wildcard matching or '?' for substitution. +.sp +Note that if the '*' is used, then be aware that the order of entries in the file is important. The '*' on its own is used to ensure a default fallback context is assigned and should be the last entry in the \fIobject_type\fR block. +.RE +.I context +.RS +The security context that will be applied to the object. +.RE +.RE +.sp +The following example is for SE-PostgreSQL: +.sp +# ./contexts/sepgsql_contexts file +.br +# object_type object_name context +.br +db_database my_database system_u:object_r:sepgsql_db_t:s0 +.br +db_database * system_u:object_r:sepgsql_db_t:s0 +.br +db_schema *.* system_u:object_r:sepgsql_schema_t:s0 +.br +db_tuple row_low system_u:object_r:sepgsql_table_t:s0 +.br +db_tuple row_high system_u:object_r:sepgsql_table_t:s0:c1023 +.br +db_tuple *.*.* system_u:object_r:sepgsql_table_t:s0 +. +.SH "NOTES" +.IP "1." 4 +A suitable database contexts file needs to be written for the target RDBMS and the \fBSELABEL_OPT_PATH\fR option must be used in \fBselabel_open\fR(3) to load it. +.IP "2." 4 +The hierarchy of the namespace for database objects depends on the RDBMS, however the \fIselabel*\fR interfaces do not have any specific support for a namespace hierarchy. +.sp +SE-PostgreSQL has a namespace hierarchy where a database is the top level object with the schema being the next level. Under the schema object there can be other types of objects such as tables and procedures. This hierarchy is supported as follows: +.RS +.RS +.sp +If a security context is required for "my_table" table in the "public" +schema within the "postgres" database, then the \fBselabel_lookup\fR(3) +parameters for \fIobject_type\fR would be \fBSELABEL_DB_TABLE\fR and the +\fIobject_name\fR would be "postgres.public.my_table", the security +context (if available), would be returned in \fIcontext\fR. +.RE +.RE +.IP "3." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_sepgsql_context_path "(3), " freecon "(3), " selinux_config "(5) " diff --git a/man/man5/selabel_file.5 b/man/man5/selabel_file.5 new file mode 100644 index 0000000..e97bd82 --- /dev/null +++ b/man/man5/selabel_file.5 @@ -0,0 +1,220 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_file" "5" "01 Dec 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_file \- userspace SELinux labeling interface and configuration file format for the file contexts backend +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +. +.SH "DESCRIPTION" +The file contexts backend maps from pathname/mode combinations into security contexts. It is used to find the appropriate context for each file when relabeling a file system. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes, however the following \fIerrno\fR is clarified further for the file contexts backend: +.RS +.TP +.B ENOENT +No context corresponding to the \fIpath\fR and \fImode\fR was found - This will also be returned when the file contexts series of files have a context of \fB<>\fR against the \fIpath\fR (see the \fBFILE FORMAT\fR section). +.RE +.sp +The \fIpath\fR argument should be set to the full pathname of the file whose assigned context is being checked. The \fImode\fR argument should be set to the mode bits of the file, as determined by \fBlstat\fR(2). \fImode\fR may be zero, however full matching may not occur. +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine a file context. +. +.SH "OPTIONS" +In addition to the global options described in +.BR selabel_open (3), +this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard file contexts file. This value is also used as the base name for determining the names of local customization files. +.TP +.B SELABEL_OPT_BASEONLY +A non-null value for this option indicates that any local customizations to the file contexts mapping should be ignored. +.TP +.B SELABEL_OPT_SUBSET +A non-null value for this option is interpreted as a path prefix, for example "/etc". Only file context specifications with starting with a first component that prefix matches the given prefix are loaded. This may increase lookup performance, however any attempt to look up a path not starting with the given prefix may fail. This optimization is no longer required due to the use of +.I file_contexts.bin +files and is deprecated. +.RE +. +.SH "FILES" +The file context files used to retrieve the default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy file contexts location (as returned by \fBselinux_file_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +If \fBSELABEL_OPT_BASEONLY\fR is set, then the following files will be processed: +.RS +.IP "1." 4 +The mandatory file contexts file that is either the fully qualified file name from \fISELABEL_OPT_PATH.value\fR or if \fINULL\fR, then the path returned by \fBselinux_file_context_path\fR(3). +.IP "2." 4 +The optional local and distribution substitution files that perform path aliasing on the 'in memory' version of the file contexts file. +.br +These files have the same name as the mandatory file contexts file with the extensions \fI.subs\fR and \fI.subs_dist\fR added. +.RE +.sp +If the \fBSELABEL_OPT_BASEONLY\fR is not set, then the following files will be processed: +.RS +.IP "1." 4 +The mandatory file contexts file that is either the fully qualified file name from \fISELABEL_OPT_PATH.value\fR or if \fINULL\fR, then the path returned by \fBselinux_file_context_path\fR(3). +.IP "2." 4 +The optional local customizations file that has the same name as the mandatory file contexts file with the extension \fI.local\fR added. +.br +\fBselinux_file_context_local_path\fR(3) will return the default path to this file. +.IP "3." 4 +The optional user home directory customizations file that has the same name as the mandatory file contexts file with the extension \fI.homedirs\fR added. +.br +\fBselinux_file_context_homedir_path\fR(3) will return the default path to this file. +.IP "4." 4 +The optional local and distribution substitution files that perform any path aliasing on the 'in memory' version of the file contexts file (and the \fI.local\fR and/or \fI.homedirs\fR if present). These files have the same name as the mandatory file contexts file with the extensions \fI.subs\fR and \fI.subs_dist\fR added. +.br +\fBselinux_file_context_subs_path\fR(3) and \fBselinux_file_context_subs_dist_path\fR(3) will return the default paths to these files. +.RE +.sp +The default file context series of files are: +.RS 6 +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.local +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.homedirs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs_dist +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +Only the \fIfile_contexts\fR file is mandatory, the remainder are optional. +.sp +The entries within the file contexts series of files are shown in the \fBFILE FORMAT\fR section. +. +.SH "FILE FORMAT" +.sp +.SH "File Contexts Format" +.sp +Each line within the \fIfile_contexts\fR and the two customization files (\fI.local\fR and \fI.homedirs\fR) is as follows: +.sp +.RS +.I pathname [file_type] context +.RE +.sp +Where: +.br +.RS +.I pathname +.RS +An entry that defines the pathname that may be in the form of a regular expression. +.RE +.I file_type +.RS +An optional file type consisting of: +.RS +\fI\-b\fR - Block Device \fI\-c\fR - Character Device +.br +\fI\-d\fR - Directory \fI\-p\fR - Named Pipe +.br +\fI\-l\fR - Symbolic Link \fI\-s\fR - Socket +.br +\fI\-\-\fR - Ordinary file +.RE +.RE +.I context +.RS +This entry can be either: +.RS +.IP "a." 4 +The security context that will be assigned to the file (i.e. returned as \fIcontext\fR). +.IP "b." 4 +A value of \fB<>\fR can be used to indicate that the matching files should not be re-labeled and causes \fBselabel_lookup\fR(3) to return \-1 with \fIerrno\fR set to \fBENOENT\fR. +.RE +.RE +.RE +.sp +Example: +.RS +# ./contexts/files/file_contexts +.br +# pathname file_type context +.br +/.* system_u:object_r:default_t:s0 +.br +/[^/]+ \-\- system_u:object_r:etc_runtime_t:s0 +.br +/tmp/.* <> +.RE +.sp +.SH "Substitution File Format" +.sp +Each line within the substitution files (\fI.subs\fR and \fI.subs_dist\fR) has the form: +.RS +.I subs_pathname pathname +.RE +.sp +Where: +.RS +.I pathname +.RS +A path that matches an entry in one or more of the file contexts policy configuration file. +.RE +.I subs_pathname +.RS +The path that will be aliased (considered equivalent) with pathname by the look up process. +.RE +.RE +.sp +Example: +.RS +# ./contexts/files/file_contexts.subs +.br +# pathname subs_pathname +.br +/myweb /var/www +.br +/myspool /var/spool/mail +.sp +Using the above example, when \fBselabel_lookup\fR(3) is passed a path of +\fI/myweb/index.html\fR the function will substitute the \fI/myweb\fR +component with \fI/var/www\fR, therefore the path used is: +.sp +.RS +.I /var/www/index.html +.RE +.RE +. +.SH "NOTES" +.IP "1." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +.IP "2." 4 +If the size of file contexts series of files contain many entries, then \fBselabel_open\fR(3) may have a delay as it reads in the files, and if +requested validates the entries. +.IP "3." 4 +Depending on the version of SELinux it is possible that a \fIfile_contexts.template\fR file may also be present, however this is now deprecated. +.br +The template file has the same format as the \fIfile_contexts\fR file and may also contain the keywords \fBHOME_ROOT\fR, \fBHOME_DIR\fR, \fBROLE\fR and \fBUSER\fR. This functionality has now been moved to the policy store and managed by \fBsemodule\fR(8) and \fBgenhomedircon\fR(8). +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_file_context_path "(3), " freecon "(3), " selinux_config "(5), " lstat "(2), "selinux_file_context_subs_path "(3), " selinux_file_context_subs_dist_path "(3), " selinux_file_context_homedir_path "(3), "selinux_file_context_local_path "(3), " semodule "(8), " genhomedircon "(8) " diff --git a/man/man5/selabel_media.5 b/man/man5/selabel_media.5 new file mode 100644 index 0000000..b7c28e3 --- /dev/null +++ b/man/man5/selabel_media.5 @@ -0,0 +1,91 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_media" "5" "29 Nov 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_media \- userspace SELinux labeling interface and configuration file format for the media contexts backend +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +. +.SH "DESCRIPTION" +The media contexts backend maps from media device names such as "cdrom" or "floppy" into security contexts. It is used to find the appropriate context for establishing context mounts on these devices. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +The integer lookup argument is currently unused and should be set to zero. +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR +by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +behaves identically to \fBselabel_lookup\fR(3) but does not perform context +translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the media context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard \fImedia\fR contexts file. +. +.SH "FILES" +The media context file used to retrieve a default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\FR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy media contexts location (as returned by \fBselinux_media_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +The default media contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/files/media +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line within the \fImedia\fR file is as follows: +.RS +.I device_name context +.RE +.sp +Where: +.RS +.I device_name +.RS +The media identifier (e.g. cdrom, floppy, disk and usb). +.RE +.I context +.RS +The context to be used for labeling the device. +.RE +.RE +.sp +Example: +.RS +# contexts/files/media +.br +cdrom system_u:object_r:removable_device_t +.br +floppy system_u:object_r:removable_device_t +.br +disk system_u:object_r:fixed_disk_device_t +. +.SH "NOTES" +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If +this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_media_context_path "(3), " freecon "(3), " selinux_config "(5) " diff --git a/man/man5/selabel_x.5 b/man/man5/selabel_x.5 new file mode 100644 index 0000000..198a3e1 --- /dev/null +++ b/man/man5/selabel_x.5 @@ -0,0 +1,166 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_x" "5" "29 Nov 2011" "Security Enhanced Linux" "SELinux API documentation" +.SH "NAME" +selabel_x \- userspace SELinux labeling interface and configuration file format for the X Window System contexts backend. This backend is also used to determine the default context for labeling remotely connected X clients +. +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "DESCRIPTION" +The X contexts backend maps from X Window System object names into security contexts. It is used to find the appropriate context for X Window System objects whose significance and/or usage semantics are determined primarily by name. The returned \fIcontext\fR must be freed using \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) describes the function with its return and error codes. +.sp +This backend is also used to determine the default context for labeling remotely connected X clients. +.sp +The \fIobject_type\fR argument should be set to one of the following values: +.RS +.TP +.B SELABEL_X_PROP +The +.I object_name +argument specifies the name of a window property, such as "WM_NAME". +.TP +.B SELABEL_X_SELN +The +.I object_name +argument specifies the name of a selection, such as "PRIMARY". +.TP +.B SELABEL_X_EXT +The +.I object_name +argument specifies the name of a protocol extension, such as "RENDER". +.TP +.B SELABEL_X_EVENT +The +.I object_name +argument specifies the name of an event type, such as "X11:ButtonPress". +.TP +.B SELABEL_X_CLIENT +The +.I object_name +argument is ignored, however it should be set to either \fI*\fR (an asterisk or 'wildcard' that will select the default entry) or a specific entry such as "remote" in the X contexts file as shown in the \fBEXAMPLE\fR section. The default context for labeling remote X clients is then returned. +.TP +.B SELABEL_X_POLYPROP +Like +.BR SELABEL_X_PROP , +but checks if the property was marked as being polyinstantiated. See \fBNOTES\fR below. +.TP +.B SELABEL_X_POLYSELN +Like +.BR SELABEL_X_SELN , +but checks if the selection was marked as being polyinstantiated. See \fBNOTES\fR below. +.RE +.sp +Any messages generated by \fBselabel_lookup\fR(3) are sent to \fIstderr\fR by default, although this can be changed by \fBselinux_set_callback\fR(3). +.sp +.B selabel_lookup_raw +behaves identically to \fBselabel_lookup\fR but does not perform context translation. +.sp +The \fBFILES\fR section details the configuration files used to determine the X object context. +. +.SH "OPTIONS" +In addition to the global options described in \fBselabel_open\fR(3), this backend recognizes the following options: +.RS +.TP +.B SELABEL_OPT_PATH +A non-null value for this option specifies a path to a file that will be opened in lieu of the standard X contexts file (see the \fBFILES\fR section for details). +.RE +. +.SH "FILES" +The X context file used to retrieve a default context depends on the \fBSELABEL_OPT_PATH\fR parameter passed to \fBselabel_open\fR(3). If \fINULL\fR, then the \fBSELABEL_OPT_PATH\fR value will default to the active policy X contexts location (as returned by \fBselinux_x_context_path\fR(3)), otherwise the actual \fBSELABEL_OPT_PATH\fR value specified is used. +.sp +The default X object contexts file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/x_contexts +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +The entries within the X contexts file are shown in the \fBObject Name String Values\fR and \fBFILE FORMAT\fR sections. +. +.SH "Object Name String Values" +The string name assigned to each \fIobject_type\fR argument that can be present in the X contexts file are: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Text Name +SELABEL_X_PROP@property +SELABEL_X_SELN@selection +SELABEL_X_EXT@extension +SELABEL_X_EVENT@event +SELABEL_X_CLIENT@client +SELABEL_X_POLYPROP@poly_property +SELABEL_X_POLYSELN@poly_selection +.TE +. +.SH "FILE FORMAT" +Each line within the X contexts file is as follows: +.RS +.I object_type object_name context +.RE +.sp +Where: +.RS +.I object_type +.RS +This is the string representation of the object type shown in the \fBObject Name String Values\fR section. +There can be multiple lines with the same \fIobject_type\fR string that will form a block of entries (each with a different \fIobject_name\fR entry). +.RE +.I object_name +.RS +These are the object names of the specific X-server resource such as +\fBPRIMARY\fR, \fBCUT_BUFFER0\fR etc. They are generally defined in the +X-server source code (\fIprotocol.txt\fR and \fIBuiltInAtoms\fR in the +dix directory of the xorg\-server source package). +The entry can contain '*' for wildcard matching or '?' for substitution. +Note that if the '*' is used, then be aware that the order of entries in the file is important. The '*' on its own is used to ensure a default fallback context is assigned and should be the last entry in the \fIobject_type\fR block. +.RE +.I context +.RS +The security context that will be applied to the object. +.RE +.RE +.sp +Example 1: +.sp +.nf +# object_type object_name context +selection PRIMARY system_u:object_r:clipboard_xselection_t:s0 +selection * system_u:object_r:xselection_t:s0 +.fi +.sp +Example 2 - This example shows how a client entry can be configured to +ensure an entry is always found: +.sp +.nf +# object_type object_name context +client * system_u:object_r:remote_t:s0 +.fi +. +.SH "NOTES" +.IP "1." 4 +Properties and selections are marked as either polyinstantiated or not. For these name types, the "POLY" option searches only the names marked as being polyinstantiated, while the other option searches only the names marked as not being polyinstantiated. Users of the interface should check both mappings, optionally taking action based on the result (e.g. polyinstantiating the object). +.IP "2." 4 +If contexts are to be validated, then the global option \fBSELABEL_OPT_VALIDATE\fR must be set before calling \fBselabel_open\fR(3). If this is not set, then it is possible for an invalid context to be returned. +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_x_context_path "(3), " freecon "(3), " selinux_config "(5) " diff --git a/man/man5/sepgsql_contexts.5 b/man/man5/sepgsql_contexts.5 new file mode 100644 index 0000000..ec2bb47 --- /dev/null +++ b/man/man5/sepgsql_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_db.5 diff --git a/man/man5/service_seusers.5 b/man/man5/service_seusers.5 new file mode 100644 index 0000000..385a326 --- /dev/null +++ b/man/man5/service_seusers.5 @@ -0,0 +1,67 @@ +.TH "service_seusers" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +service_seusers \- The SELinux GNU/Linux user and service to SELinux user mapping configuration files +. +.SH "DESCRIPTION" +These are optional files that allow services to define an SELinux user when authenticating via SELinux-aware login applications such as +.BR PAM "(8). " +.sp +There is one file for each GNU/Linux user name that will be required to run a service with a specific SELinux user name. +.sp +The path for each configuration file is formed by the path returned by +.BR selinux_policy_root "(3) with " +.IR /logins/username +appended (where \fIusername\fR is a file representing the GNU/Linux user name). The default services directory is located at: +.RS +.I /etc/selinux/{SELINUXTYPE}/logins +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR getseuser "(3) reads this file to map services to an SELinux user. " +. +.SH "FILE FORMAT" +Each line within the \fIusername\fR file is formatted as follows with each component separated by a colon: +.RS +.IB service : seuser \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I service +.RS +The service name used by the application. +.RE +.I seuser +.RS +The SELinux user name. +.RE +.I range +.RS +The range for MCS/MLS policies. +.RE +.RE +. +.SH "EXAMPLES" +Example 1 - for the 'root' user: +.RS +# ./logins/root +.br +ipa:user_u:s0 +.br +this_service:unconfined_u:s0 +.RE +.sp +Example 2 - for GNU/Linux user 'rch': +.RS +# ./logins/rch +.br +ipa:unconfined_u:s0 +.br +that_service:unconfined_u:s0 +.RE +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_policy_root "(3), " getseuser "(3), " selinux_config "(5) " diff --git a/man/man5/seusers.5 b/man/man5/seusers.5 new file mode 100644 index 0000000..2512560 --- /dev/null +++ b/man/man5/seusers.5 @@ -0,0 +1,63 @@ +.TH "seusers" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +seusers \- The SELinux GNU/Linux user to SELinux user mapping configuration file +. +.SH "DESCRIPTION" +The +.I seusers +file contains a list GNU/Linux user to SELinux user mapping for use by SELinux-aware login applications such as \fBPAM\fR(8). +.sp +.BR selinux_usersconf_path "(3) " +will return the active policy path to this file. The default SELinux users mapping file is located at: +.RS +.I /etc/selinux/{SELINUXTYPE}/seusers +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +.BR getseuserbyname "(3) reads this file to map a GNU/Linux user or group to an SELinux user. " +. +.SH "FILE FORMAT" +Each line of the +.I seusers +configuration file consists of the following: +.sp +.RS +\fR[\fB%\fIgroup_id\fR]|[\fIuser_id\fR]\fB:\fIseuser_id\fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +\fIgroup_id\fR|\fIuser_id +.RS +\fRThe GNU/Linux user id, or if preceded by the percentage (\fB%\fR) symbol, then a GNU/Linux group id. +.br +An optional entry set to \fB__default__\fR can be provided as a fall back if required. +.RE +.I seuser_id +.RS +The SELinux user identity. +.RE +.I range +.RS +The optional level or range for an MLS/MCS policy. +.RE +.RE +. +.SH "EXAMPLE" +# ./seusers +.br +system_u:system_u:s0\-s15:c0.c255 +.br +root:root:s0\-s15:c0.c255 +.br +fred:user_u:s0 +.br +__default__:user_u:s0 +.br +%user_group:user_u:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_usersconf_path "(3), " getseuserbyname "(3), " selinux_config "(5) " diff --git a/man/man5/user_contexts.5 b/man/man5/user_contexts.5 new file mode 100644 index 0000000..fc53d6c --- /dev/null +++ b/man/man5/user_contexts.5 @@ -0,0 +1,82 @@ +.TH "user_contexts" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +user_contexts \- The SELinux user contexts configuration files +. +.SH "DESCRIPTION" +These optional user context configuration files contain entries that allow SELinux-aware login applications such as +.BR PAM (8) +(running in their own process context), to determine the context that a users login session should run under. +.sp +SELinux-aware login applications generally use one or more of the following libselinux functions that read these files from the active policy path: +.RS +.BR get_default_context (3) +.br +.BR get_ordered_context_list (3) +.br +.BR get_ordered_context_list_with_level (3) +.br +.BR get_default_context_with_level (3) +.br +.BR get_default_context_with_role (3) +.br +.BR get_default_context_with_rolelevel (3) +.br +.BR query_user_context (3) +.br +.BR manual_user_enter_context (3) +.RE +.sp +There can be one file for each SELinux user configured on the system. The file path is formed using the path returned by +.BR \%selinux_user_contexts_path (3) +for the active policy, with the SELinux user name appended, for example: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/unconfined_u +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/users/xguest_u +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +.sp +These files contain context information as described in the +.B FILE FORMAT +section. +. +.SH "FILE FORMAT" +Each line in the user context configuration file consists of the following: +.RS +.I login_process user_login_process +.RE +.sp +Where: +.RS +.I login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the login process context. +.RE +.I user_login_process +.RS +This consists of a \fIrole\fB:\fItype\fR[\fB:\fIrange\fR] entry that represents the user login process context. +.RE +.RE +. +.SH "EXAMPLE" +# Example for xguest_u at /etc/selinux/targeted/contexts/users/xguest_u +.br +system_r:crond_t:s0 xguest_r:xguest_t:s0 +.br +system_r:initrc_t:s0 xguest_r:xguest_t:s0 +.br +system_r:local_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:remote_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:sshd_t:s0 xguest_r:xguest_t:s0 +.br +system_r:xdm_t:s0 xguest_r:xguest_t:s0 +.br +xguest_r:xguest_t:s0 xguest_r:xguest_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " selinux_user_contexts_path "(3), " PAM "(8), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " diff --git a/man/man5/virtual_domain_context.5 b/man/man5/virtual_domain_context.5 new file mode 100644 index 0000000..a76fe14 --- /dev/null +++ b/man/man5/virtual_domain_context.5 @@ -0,0 +1,40 @@ +.TH "virtual_domain_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +virtual_domain_context \- The SELinux virtual machine domain context configuration file +. +.SH "DESCRIPTION" +The +.I virtual_domain_context +file contains a list of domain contexts that are available for use by the SELinux-aware virtualization API libvirt (see \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_domain_context_path "(3) " +will return the active policy path to this file. The default virtual domain context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_domain_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the file consists of an entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that can be used as a virtual domain context. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/virtual_domain_context +.br +system_u:object_r:svirt_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_domain_context_path "(3), " selinux_config "(5) " diff --git a/man/man5/virtual_image_context.5 b/man/man5/virtual_image_context.5 new file mode 100644 index 0000000..df1c0e9 --- /dev/null +++ b/man/man5/virtual_image_context.5 @@ -0,0 +1,42 @@ +.TH "virtual_image_context" "5" "28-Nov-2011" "Security Enhanced Linux" "SELinux configuration" +.SH "NAME" +virtual_image_context \- The SELinux virtual machine image context configuration file +. +.SH "DESCRIPTION" +The +.I virtual_image_context +file contains a list of image contexts for use by the SELinux-aware virtualization API libvirt (see \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_image_context_path "(3) " +will return the active policy path to this file. The default virtual image context file is: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_image_context +.RE +.sp +Where \fI{SELINUXTYPE}\fR is the entry from the selinux configuration file \fIconfig\fR (see \fBselinux_config\fR(5)). +. +.SH "FILE FORMAT" +Each line in the file consists of an entry as follows: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Where: +.RS +.I user role type range +.RS +A user, role, type and optional range (for MCS/MLS) separated by colons (:) that can be used as a virtual image context. +.RE +.RE +. +.SH "EXAMPLE" +# ./contexts/virtual_image_context +.br +system_u:object_r:svirt_image_t:s0 +.br +system_u:object_r:svirt_content_t:s0 +. +.SH "SEE ALSO" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_image_context_path "(3), " selinux_config "(5) " diff --git a/man/man5/x_contexts.5 b/man/man5/x_contexts.5 new file mode 100644 index 0000000..3796d2a --- /dev/null +++ b/man/man5/x_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_x.5 diff --git a/man/man8/avcstat.8 b/man/man8/avcstat.8 new file mode 100644 index 0000000..2c4bce1 --- /dev/null +++ b/man/man8/avcstat.8 @@ -0,0 +1,35 @@ +.TH "avcstat" "8" "18 Nov 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +avcstat \- Display SELinux AVC statistics +. +.SH "SYNOPSIS" +.B avcstat +.RB [ \-c ] +.RB [ \-f +.IR status_file ] +.RI [ interval ] +. +.SH "DESCRIPTION" +Display SELinux AVC statistics. If the +.I interval +parameter is specified, the program will loop, displaying updated +statistics every +.I interval +seconds. +Relative values are displayed by default. +. +.SH OPTIONS +.TP +.B \-c +Display the cumulative values. +.TP +.B \-f +Specifies the location of the AVC statistics file, defaulting to +.IR /sys/fs/selinux/avc/cache_stats . +. +.SH AUTHOR +This manual page was written by Dan Walsh . +The program was written by James Morris . +. +.SH "SEE ALSO" +.BR selinux (8) diff --git a/man/man8/booleans.8 b/man/man8/booleans.8 new file mode 100644 index 0000000..d4ca9c4 --- /dev/null +++ b/man/man8/booleans.8 @@ -0,0 +1,58 @@ +.TH "booleans" "8" "11 Aug 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +booleans \- Policy booleans enable runtime customization of SELinux policy +. +.SH "DESCRIPTION" +This manual page describes SELinux policy booleans. +.BR +The SELinux policy can include conditional rules that are enabled or +disabled based on the current values of a set of policy booleans. +These policy booleans allow runtime modification of the security +policy without having to load a new policy. + +For example, the boolean httpd_enable_cgi allows the httpd daemon to +run cgi scripts if it is enabled. If the administrator does not want +to allow execution of cgi scripts, he can simply disable this boolean +value. + +The policy defines a default value for each boolean, typically false. +These default values can be overridden via local settings created via the +.BR setsebool (8) +utility, using +.B \-P +to make the setting persistent across reboots. The +.B system\-config\-securitylevel +tool provides a graphical interface for altering +the settings. The +.BR load_policy (8) +program will preserve +current boolean settings upon a policy reload by default, or can +optionally reset booleans to the boot-time defaults via the +.B \-b +option. + +Boolean values can be listed by using the +.BR getsebool (8) +utility and passing it the +.B \-a +option. + +Boolean values can also be changed at runtime via the +.BR setsebool (8) +utility or the +.BR togglesebool (8) +utility. By default, these utilities only change the +current boolean value and do not affect the persistent settings, +unless the +.B \-P +option is used to setsebool. +. +.SH AUTHOR +This manual page was written by Dan Walsh . +The SELinux conditional policy support was developed by Tresys Technology. +. +.SH "SEE ALSO" +.BR getsebool (8), +.BR setsebool (8), +.BR selinux (8), +.BR togglesebool (8) diff --git a/man/man8/getenforce.8 b/man/man8/getenforce.8 new file mode 100644 index 0000000..70b9921 --- /dev/null +++ b/man/man8/getenforce.8 @@ -0,0 +1,18 @@ +.TH "getenforce" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +getenforce \- get the current mode of SELinux +. +.SH "SYNOPSIS" +.B getenforce +. +.SH "DESCRIPTION" +.B getenforce +reports whether SELinux is enforcing, permissive, or disabled. +. +.SH AUTHOR +Dan Walsh, +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setenforce (8), +.BR selinuxenabled (8) diff --git a/man/man8/getsebool.8 b/man/man8/getsebool.8 new file mode 100644 index 0000000..d70bf1e --- /dev/null +++ b/man/man8/getsebool.8 @@ -0,0 +1,37 @@ +.TH "getsebool" "8" "11 Aug 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +getsebool \- get SELinux boolean value(s) +. +.SH "SYNOPSIS" +.B getsebool +.RB [ \-a ] +.RI [ boolean ] +. +.SH "DESCRIPTION" +.B getsebool +reports where a particular SELinux boolean or +all SELinux booleans are on or off +In certain situations a boolean can be in one state with a pending +change to the other state. getsebool will report this as a pending change. +The pending value indicates +the value that will be applied upon the next boolean commit. + +The setting of boolean values occurs in two stages; first the pending +value is changed, then the booleans are committed, causing their +active values to become their pending values. This allows a group of +booleans to be changed in a single transaction, by setting all of +their pending values as desired and then committing once. +. +.SH OPTIONS +.TP +.B \-a +Show all SELinux booleans. +. +.SH AUTHOR +This manual page was written by Dan Walsh . +The program was written by Tresys Technology. +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setsebool (8), +.BR booleans (8) diff --git a/man/man8/matchpathcon.8 b/man/man8/matchpathcon.8 new file mode 100644 index 0000000..50c0d39 --- /dev/null +++ b/man/man8/matchpathcon.8 @@ -0,0 +1,62 @@ +.TH "matchpathcon" "8" "21 April 2005" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +matchpathcon \- get the default SELinux security context for the specified path from the file contexts configuration +. +.SH "SYNOPSIS" +.B matchpathcon +.RB [ \-V ] +.RB [ \-N ] +.RB [ \-n ] +.RB [ \-m +.IR type ] +.RB [ \-f +.IR file_contexts_file ] +.RB [ \-p +.IR prefix ] +.RB [ \-P +.IR policy_root_path ] +.I filepath... +. +.SH "DESCRIPTION" +.BR matchpathcon +queries the system policy and outputs the default security context associated with the filepath. + +.B Note: +Identical paths can have different security contexts, depending on the file +type (regular file, directory, link file, char file ...). + +.B matchpathcon +will also take the file type into consideration in determining the default security context if the file exists. If the file does not exist, no file type matching will occur. +. +.SH OPTIONS +.TP +.BI \-m " type" +Force file type for the lookup. +Valid types are +.BR file ", " dir ", "pipe ", " chr_file ", " blk_file ", " +.BR lnk_file ", " sock_file . +.TP +.B \-n +Do not display path. +.TP +.B \-N +Do not use translations. +.TP +.BI \-f " file_context_file" +Use alternate file_context file +.TP +.BI \-p " prefix" +Use prefix to speed translations +.TP +.BI \-P " policy_root_path" +Use alternate policy root path +.TP +.B \-V +Verify file context on disk matches defaults +. +.SH AUTHOR +This manual page was written by Dan Walsh . +. +.SH "SEE ALSO" +.BR selinux "(8), " +.BR matchpathcon (3) diff --git a/man/man8/sefcontext_compile.8 b/man/man8/sefcontext_compile.8 new file mode 100644 index 0000000..4eae173 --- /dev/null +++ b/man/man8/sefcontext_compile.8 @@ -0,0 +1,71 @@ +.TH "sefcontext_compile" "8" "12 Aug 2015" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +sefcontext_compile \- compile file context regular expression files +. +.SH "SYNOPSIS" +.B sefcontext_compile +.RB [ \-o +.IR outputfile ] +.RB [ \-p +.IR policyfile ] +.I inputfile +. +.SH "DESCRIPTION" +.B sefcontext_compile +is used to compile file context regular expressions into +.BR pcre (3) +format. +.sp +The compiled file is used by libselinux file labeling functions. +.sp +By default +.B sefcontext_compile +writes the compiled pcre file with the +.B .bin +suffix appended (e.g. \fIinputfile\fB.bin\fR). +.SH OPTIONS +.TP +.B \-o +Specify an +.I outputfile +that must be a fully qualified file name as the +.B .bin +suffix is not automatically added. +.TP +.B \-p +Specify a binary +.I policyfile +that will be used to validate the context entries in the +.I inputfile +.br +If an invalid context is found the pcre formatted file will not be written and +an error will be returned. + +.SH "RETURN VALUE" +On error -1 is returned. On success 0 is returned. + +.SH "EXAMPLES" +.B Example 1: +.br +sefcontext_compile /etc/selinux/targeted/contexts/files/file_contexts +.sp +Results in the following file being generated: +.RS +/etc/selinux/targeted/contexts/files/file_contexts.bin +.RE +.sp +.B Example 2: +.br +sefcontext_compile -o new_fc.bin /etc/selinux/targeted/contexts/files/file_contexts +.sp +Results in the following file being generated in the cwd: +.RS +new_fc.bin +.RE +. +.SH AUTHOR +Dan Walsh, +. +.SH "SEE ALSO" +.BR selinux (8), +.BR semanage (8), diff --git a/man/man8/selinux.8 b/man/man8/selinux.8 new file mode 100644 index 0000000..bf23b65 --- /dev/null +++ b/man/man8/selinux.8 @@ -0,0 +1,113 @@ +.TH "selinux" "8" "29 Apr 2005" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +SELinux \- NSA Security-Enhanced Linux (SELinux) +. +.SH "DESCRIPTION" +NSA Security-Enhanced Linux (SELinux) is an implementation of a +flexible mandatory access control architecture in the Linux operating +system. The SELinux architecture provides general support for the +enforcement of many kinds of mandatory access control policies, +including those based on the concepts of Type Enforcement®, Role- +Based Access Control, and Multi-Level Security. Background +information and technical documentation about SELinux can be found at +http://www.nsa.gov/research/selinux. + +The +.I /etc/selinux/config +configuration file controls whether SELinux is +enabled or disabled, and if enabled, whether SELinux operates in +permissive mode or enforcing mode. The +.B SELINUX +variable may be set to +any one of disabled, permissive, or enforcing to select one of these +options. The disabled option completely disables the SELinux kernel +and application code, leaving the system running without any SELinux +protection. The permissive option enables the SELinux code, but +causes it to operate in a mode where accesses that would be denied by +policy are permitted but audited. The enforcing option enables the +SELinux code and causes it to enforce access denials as well as +auditing them. Permissive mode may yield a different set of denials +than enforcing mode, both because enforcing mode will prevent an +operation from proceeding past the first denial and because some +application code will fall back to a less privileged mode of operation +if denied access. + +The +.I /etc/selinux/config +configuration file also controls what policy +is active on the system. SELinux allows for multiple policies to be +installed on the system, but only one policy may be active at any +given time. At present, multiple kinds of SELinux policy exist: targeted, +mls for example. The targeted policy is designed as a policy where most +user processes operate without restrictions, and only specific services are +placed into distinct security domains that are confined by the policy. +For example, the user would run in a completely unconfined domain +while the named daemon or apache daemon would run in a specific domain +tailored to its operation. The MLS (Multi-Level Security) policy is designed +as a policy where all processes are partitioned into fine-grained security +domains and confined by policy. MLS also supports the Bell And LaPadula model, where processes are not only confined by the type but also the level of the data. + +You can +define which policy you will run by setting the +.B SELINUXTYPE +environment variable within +.IR /etc/selinux/config . +You must reboot and possibly relabel if you change the policy type to have it take effect on the system. +The corresponding +policy configuration for each such policy must be installed in the +.I /etc/selinux/{SELINUXTYPE}/ +directories. + +A given SELinux policy can be customized further based on a set of +compile-time tunable options and a set of runtime policy booleans. +.B \%system\-config\-selinux +allows customization of these booleans and tunables. + +Many domains that are protected by SELinux also include SELinux man pages explaining how to customize their policy. +. +.SH "FILE LABELING" +All files, directories, devices ... have a security context/label associated with them. These context are stored in the extended attributes of the file system. +Problems with SELinux often arise from the file system being mislabeled. This can be caused by booting the machine with a non SELinux kernel. If you see an error message containing file_t, that is usually a good indicator that you have a serious problem with file system labeling. + +The best way to relabel the file system is to create the flag file +.I /.autorelabel +and reboot. +.BR system\-config\-selinux , +also has this capability. The +.BR restorecon / fixfiles +commands are also available for relabeling files. +. +.SH AUTHOR +This manual page was written by Dan Walsh . +. +.SH FILES +.I /etc/selinux/config +. +.SH "SEE ALSO" +.ad l +.nh +.BR booleans (8), +.BR setsebool (8), +.BR sepolicy (8), +.BR system-config-selinux (8), +.BR togglesebool (8), +.BR fixfiles (8), +.BR restorecon (8), +.BR setfiles (8), +.BR semanage (8), +.BR sepolicy (8) +.BR seinfo (8), +.BR sesearch (8) + +Every confined service on the system has a man page in the following format: +.br + +.BR _selinux (8) + +For example, httpd has the +.BR httpd_selinux (8) +man page. + +.B man -k selinux + +Will list all SELinux man pages. diff --git a/man/man8/selinuxenabled.8 b/man/man8/selinuxenabled.8 new file mode 100644 index 0000000..5cd7a62 --- /dev/null +++ b/man/man8/selinuxenabled.8 @@ -0,0 +1,20 @@ +.TH "selinuxenabled" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxenabled \- tool to be used within shell scripts to determine if selinux is enabled +. +.SH "SYNOPSIS" +.B selinuxenabled +. +.SH "DESCRIPTION" +Indicates whether SELinux is enabled or disabled. +. +.SH "EXIT STATUS" +It exits with status 0 if SELinux is enabled and 1 if it is not enabled. +. +.SH AUTHOR +Dan Walsh, +. +.SH "SEE ALSO" +.BR selinux (8), +.BR setenforce (8), +.BR getenforce (8) diff --git a/man/man8/selinuxexeccon.8 b/man/man8/selinuxexeccon.8 new file mode 100644 index 0000000..194740d --- /dev/null +++ b/man/man8/selinuxexeccon.8 @@ -0,0 +1,27 @@ +.TH "selinuxexeccon" "8" "14 May 2011" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +selinuxexeccon \- report SELinux context used for this executable +. +.SH "SYNOPSIS" +.B selinuxexeccon +.I command +.RI [ fromcon ] +. +.SH "DESCRIPTION" +.B selinuxexeccon +reports the SELinux process context for the specified command from the specified context or the current context. +. +.SH EXAMPLE +.nf +# selinuxexeccon /usr/bin/passwd +staff_u:staff_r:passwd_t:s0-s0:c0.c1023 + +# selinuxexeccon /usr/sbin/sendmail system_u:system_r:httpd_t:s0 +system_u:system_r:system_mail_t:s0 +.fi +. +.SH AUTHOR +This manual page was written by Dan Walsh . +. +.SH "SEE ALSO" +.BR secon (8) diff --git a/man/man8/setenforce.8 b/man/man8/setenforce.8 new file mode 100644 index 0000000..702041d --- /dev/null +++ b/man/man8/setenforce.8 @@ -0,0 +1,31 @@ +.TH "setenforce" "8" "7 April 2004" "dwalsh@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +setenforce \- modify the mode SELinux is running in +. +.SH "SYNOPSIS" +.B setenforce +.RB [ Enforcing | Permissive | 1 | 0 ] +. +.SH "DESCRIPTION" +Use +.B Enforcing +or +.B 1 +to put SELinux in enforcing mode. +.br +Use +.B Permissive +or +.B 0 +to put SELinux in permissive mode. + +If SELinux is disabled and you want to enable it, or SELinux is enabled and you want to disable it, please see +.BR selinux (8). +. +.SH AUTHOR +Dan Walsh, +. +.SH "SEE ALSO" +.BR selinux (8), +.BR getenforce (8), +.BR selinuxenabled (8) diff --git a/man/man8/togglesebool.8 b/man/man8/togglesebool.8 new file mode 100644 index 0000000..8f775ca --- /dev/null +++ b/man/man8/togglesebool.8 @@ -0,0 +1,22 @@ +.TH "togglesebool" "8" "26 Oct 2004" "sgrubb@redhat.com" "SELinux Command Line documentation" +.SH "NAME" +togglesebool \- flip the current value of a SELinux boolean +. +.SH "SYNOPSIS" +.B togglesebool +.I boolean... +. +.SH "DESCRIPTION" +.B togglesebool +flips the current value of a list of booleans. If the value is currently a 1, +then it will be changed to a 0 and vice versa. Only the "in memory" values are +changed; the boot-time settings are unaffected. +. +.SH AUTHOR +This man page was written by Steve Grubb +. +.SH "SEE ALSO" +.BR selinux (8), +.BR booleans (8), +.BR getsebool (8), +.BR setsebool (8) diff --git a/man/ru/man5/booleans.5 b/man/ru/man5/booleans.5 new file mode 100644 index 0000000..1471e58 --- /dev/null +++ b/man/ru/man5/booleans.5 @@ -0,0 +1,83 @@ +.TH "booleans" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +booleans \- файлы конфигурации логических переключателей SELinux +. +.SH "ОПИСАНИЕ" +Файл \fIbooleans\fR (если имеется) содержит логические переключатели, обеспечивающие поддержку определённого дистрибутива. +.sp +Файл \fIbooleans.local\fR (если имеется) содержит созданные локально логические переключатели. +.sp +Оба файла содержат список имён логических переключателей и соответствующих этим именам значений. +.sp +Обычно файл \fIbooleans\fR и/или файл \fIbooleans.local\fR отсутствуют (они устарели). Но эти файлы могут присутствовать, если имеется приложение, которое поддерживает SELinux и использует перечисленные далее функции libselinux: +.sp +.RS +.BR security_set_boolean_list "(3) " +.RS +Записывает файл \fIbooleans.local\fR, если флаг \fIpermanent\fR = \fI1\fR. +.sp +.RE +.RE +.RS +.BR security_load_booleans "(3) " +.RS +Выполняет поиск файла \fIbooleans\fR и/или файла \fIbooleans.local\fR по адресу \fBselinux_booleans_path\fR(3) (если в качестве параметра не указан конкретный путь). +.RE +.RE +.sp +\fBbooleans\fR(8) содержит подробные сведения о логических переключателях, а \fBsetsebool\fR(8) - описание того, как установить логические переключатели, которые не будут сбрасываться при перезагрузках. +.sp +\fBselinux_booleans_path\fR(3) вернёт путь активной политики к этим файлам. Файлы логических переключателей по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/booleans +.br +.I /etc/selinux/{SELINUXTYPE}/booleans.local +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Оба файла имеют один и тот же формат и содержат одно или несколько имён логических переключателей и их значения. +.sp +Формат: +.RS +.I boolean_name +.I value +.sp +.RE +Где: +.RS +.I boolean_name +.RS +Имя логического переключателя. +.RE +.I value +.RS +Значение логического переключателя по умолчанию. Может быть одним из следующих: +.RS +.IR true " | " false " | " 1 " | " 0 +.RE +.RE +.RE +.sp +Если +.B SETLOCALDEFS +указано в файле +.I config +SELinux (см. +.BR selinux_config "(5)), то " selinux_mkload_policy "(3) будет проверять наличие файла " +.I booleans.local +по адресу +.BR selinux_booleans_path (3), +а также файла +.I local.users +(см. +.BR local.users "(5)) по адресу " selinux_users_path "(3). " +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " booleans "(8), " setsebool "(8), " semanage "(8), " selinux_booleans_path "(3), " security_set_boolean_list "(3), " security_load_booleans "(3), " selinux_mkload_policy "(3), " selinux_users_path "(3), " selinux_config "(5), " local.users "(5) " + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/customizable_types.5 b/man/ru/man5/customizable_types.5 new file mode 100644 index 0000000..e001586 --- /dev/null +++ b/man/ru/man5/customizable_types.5 @@ -0,0 +1,63 @@ +.TH "customizable_types" "5" "28 ноября 2011" "Security Enhanced Linux" "SELinux configuration" +.SH "ИМЯ" +customizable_types \- файл конфигурации настраиваемых типов SELinux +. +.SH "ОПИСАНИЕ" +Файл \fIcustomizable_types\fR содержит список типов, которые можно каким-либо образом настраивать с помощью поддерживающих SELinux приложений. +.sp +Обычно это тип контекста файла, который устанавливается для файлов, к которым требуется предоставить общий доступ для определённых доменов, и когда администратору необходимо управлять этим типом вручную. +.sp +Возможность использования настраиваемых типов устарела. Рекомендуется использовать +.BR semanage (8) +.BR fcontext (8) +.BR ... (8). +Тем не менее, поддерживающие SELinux приложения, например, +.BR setfiles (8), +будут использовать эту информацию для получения списка типов, относящихся к файлам, для которых не следует повторно проставлять метки. +.sp +.BR selinux_customizable_types_path (3) +вернёт путь активной политики к этому файлу. Файл настраиваемых типов по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/customizable_types +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +.BR is_context_customizable (3) +выполняет чтение этого файла, чтобы определить, является ли контекст настраиваемым для активной политики. +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле состоит из следующих компонентов: +.RS +.I type +.RE +.sp +Где: +.RS +.I type +.RS +Определённый в политике тип, который можно настроить. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/customizable_types +.br +mount_loopback_t +.br +public_content_rw_t +.br +public_content_t +.br +swapfile_t +.br +sysadm_untrusted_content_t +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selinux_customizable_types_path "(3), " is_context_customizable "(3), " semanage "(8), " setfiles "(8), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/default_contexts.5 b/man/ru/man5/default_contexts.5 new file mode 100644 index 0000000..ca1361d --- /dev/null +++ b/man/ru/man5/default_contexts.5 @@ -0,0 +1,75 @@ +.TH "default_contexts" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +default_contexts \- файл конфигурации контекстов SELinux по умолчанию +. +.SH "ОПИСАНИЕ" +Файл конфигурации контекстов по умолчанию \fIdefault_contexts\fR содержит записи, которые позволяют поддерживающим SELinux приложениям для входа, например, +.BR PAM "(8), настроить контекст пользователя. " +.sp +Поддерживающие SELinux приложения для входа обычно используют одну или несколько из следующих функций libselinux, которые выполняют чтение этих файлов по пути активной политики: +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +.sp +Путь к файлу конфигурации контекстов по умолчанию для активной политики возвращает \fBselinux_default_contexts_path\fR(3). По умолчанию файл контекстов по умолчанию находится по адресу: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле конфигурации по умолчанию состоит из следующих компонентов: +.RS +.I login_process user_login_process [user_login_process] ... +.RE +.sp +Где: +.RS +.I login_process +.RS +Состоит из записи \fIrole\fB:\fItype\fR[\fB:\fIrange\fR], которая представляет собой контекст процесса входа, определённый в политике. +.RE +.I user_login_process +.RS +Состоит из одной или нескольких записей \fIrole\fB:\fItype\fR[\fB:\fIrange\fR], которые представляют собой контекст процесса входа пользователя, определённый в политике. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/default_contexts +.br +system_r:crond_t:s0 system_r:system_crond_t:s0 +.br +system_r:local_login_t:s0 user_r:user_t:s0 staff_r:staff_t:s0 +.br +system_r:remote_login_t:s0 user_r:user_t:s0 +.br +system_r:sshd_t:s0 user_r:user_t:s0 +.br +system_r:sulogin_t:s0 sysadm_r:sysadm_t:s0 +.br +system_r:xdm_t:s0 user_r:user_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selinux_default_contexts_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/default_type.5 b/man/ru/man5/default_type.5 new file mode 100644 index 0000000..54e2c10 --- /dev/null +++ b/man/ru/man5/default_type.5 @@ -0,0 +1,43 @@ +.TH "default_type" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +default_type \- файл конфигурации типов SELinux по умолчанию +. +.SH "ОПИСАНИЕ" +Файл \fIdefault_type\fR содержит записи, которые позволяют поддерживающим SELinux приложениям, таким как \fBnewrole\fR(1), выбирать для роли тип по умолчанию, если не предоставлен другой тип. +.sp +\fBselinux_default_type_path\fR(3) возвращает путь активной политики к этому файлу. По умолчанию файл типов по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/default_type +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +\fBget_default_type\fR(3) выполняет чтение этого файла, чтобы определить тип для активной политики. +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка внутри файла \fIdefault_type\fR форматируется записями \fIrole\fB:\fItype\fR, где: +.RS +.I role +.RS +Роль SELinux. +.RE +.I type +.RS +Тип домена, который возвращается для этой роли. +.RE +. +.SH "ПРИМЕР" +# ./contexts/default_type +.br +auditadm_r:auditadm_t +.br +user_r:user_t +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " get_default_type "(3), " newrole "(1), " selinux_default_type_path "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/failsafe_context.5 b/man/ru/man5/failsafe_context.5 new file mode 100644 index 0000000..01d6b0e --- /dev/null +++ b/man/ru/man5/failsafe_context.5 @@ -0,0 +1,68 @@ +.TH "failsafe_context" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +failsafe_context \- файл конфигурации надёжного контекста SELinux +. +.SH "ОПИСАНИЕ" +Файл +.I failsafe_context +позволяет поддерживающим SELinux приложениям, таким как +.BR PAM "(8), " +получать известный действительный контекст входа для администратора, если в других расположениях отсутствуют действительные записи по умолчанию. +.sp +.BR selinux_failsafe_context_path "(3) " +возвращает путь активной политики к этому файлу. Файл надёжного контекста по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/failsafe_context +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +Следующие функции выполняют чтение этого файла по пути активной политики, если им не удаётся получить контекст по умолчанию: +.br +.RS +.BR get_default_context "(3) " +.br +.BR get_ordered_context_list "(3) " +.br +.BR get_ordered_context_list_with_level "(3) " +.br +.BR get_default_context_with_level "(3) " +.br +.BR get_default_context_with_role "(3) " +.br +.BR get_default_context_with_rolelevel "(3) " +.br +.BR query_user_context "(3) " +.br +.BR manual_user_enter_context "(3) " +.RE +. +.SH "ФОРМАТ ФАЙЛА" +Файл состоит из следующей однострочной записи: +.RS +\fIrole\fB:\fItype\fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +.I role +.I type +.I range +.RS +Роль, тип и необязательный диапазон (для MCS/MLS), разделённые двоеточиями (:), которые формируют действительный контекст процесса входа для получения администратором доступа к системе. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/failsafe_context +.br +unconfined_r:unconfined_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selinux_failsafe_context_path "(3), " PAM "(8), " selinux_default_type_path "(3), " get_default_context "(3), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/file_contexts.5 b/man/ru/man5/file_contexts.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/ru/man5/file_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/ru/man5/file_contexts.homedirs.5 b/man/ru/man5/file_contexts.homedirs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/ru/man5/file_contexts.homedirs.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/ru/man5/file_contexts.local.5 b/man/ru/man5/file_contexts.local.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/ru/man5/file_contexts.local.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/ru/man5/file_contexts.subs.5 b/man/ru/man5/file_contexts.subs.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/ru/man5/file_contexts.subs.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/ru/man5/file_contexts.subs_dist.5 b/man/ru/man5/file_contexts.subs_dist.5 new file mode 100644 index 0000000..9c022d8 --- /dev/null +++ b/man/ru/man5/file_contexts.subs_dist.5 @@ -0,0 +1 @@ +.so man5/selabel_file.5 diff --git a/man/ru/man5/local.users.5 b/man/ru/man5/local.users.5 new file mode 100644 index 0000000..ca9f201 --- /dev/null +++ b/man/ru/man5/local.users.5 @@ -0,0 +1,72 @@ +.TH "local.users" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +local.users \- файл конфигурации локальных пользователей SELinux +. +.SH "ОПИСАНИЕ" +Файл содержит определения локальных пользователей в виде инструкций пользователей на языке политики. Этот файл имеется только в старых версиях систем SELinux, так как он устарел и был заменён службами \fBsemanage\fR(8). +.sp +\fBselinux_mkload_policy\fR(3) выполняет чтение этого файла только тогда, когда для \fBSETLOCALDEFS\fR в файле \fIconfig\fR SELinux (см. \fBselinux_config\fR(5)) установлено значение \fI1\fR. +.sp +.BR selinux_users_path "(3) " +возвращает путь активной политики к каталогу, в котором расположен файл. Файл локальных пользователей по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/local.users +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Файл состоит из одной или нескольких записей, которые заканчиваются '\fB;\fR', каждая на отдельной строке: +.RS +\fBuser \fIseuser_id \fBroles \fIrole_id\fR [[\fBlevel \fIlevel\fR] [\fBrange \fIrange\fR]]\fB;\fR +.RE +.sp +Где: +.RS +.B user +.RS +Ключевое слово user (пользователь). +.RE +.I seuser_id +.RS +Идентификатор пользователя SELinux. +.RE +.B roles +.RS +Ключевое слово roles (роли). +.RE +.I role_id +.RS +Один или несколько ранее объявленных идентификаторов ролей. Несколько идентификаторов ролей - это разделённый пробелами список, который заключён в скобки '{}'. +.RE +.B level +.RS +Если настроена система MLS/MCS, ключевое слово level (уровень). +.RE +.I level +.RS +Уровень безопасности пользователя по умолчанию. Обратите внимание, что обязательным является только компонент конфиденциальности уровня (например, s0). +.RE +.B range +.RS +Если настроена система MLS/MCS, ключевое слово range (диапазон). +.RE +.I range +.RS +Текущий уровень и уровень допуска пользователя. Они разделены дефисом '\fB-\fR' (как показано в разделе \fBПРИМЕР\fR). +.RE +.RE +. +.SH "ПРИМЕР" +# ./users/local.users +.br +user test_u roles staff_r level s0 range s0 \- s15:c0.c1023; +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " semanage "(8), " selinux_users_path "(3), " selinux_config "(5), " selinux_mkload_policy "(3) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/media.5 b/man/ru/man5/media.5 new file mode 100644 index 0000000..14f00f2 --- /dev/null +++ b/man/ru/man5/media.5 @@ -0,0 +1 @@ +.so man5/selabel_media.5 diff --git a/man/ru/man5/removable_context.5 b/man/ru/man5/removable_context.5 new file mode 100644 index 0000000..0d83ef2 --- /dev/null +++ b/man/ru/man5/removable_context.5 @@ -0,0 +1,39 @@ +.TH "removable_context" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +removable_context \- файл конфигурации SELinux-контекста съёмных устройств +. +.SH "ОПИСАНИЕ" +Этот файл содержит метку по умолчанию, которую следует использовать для съёмных устройств. +.sp +.BR selinux_removable_context_path "(3) " +вернёт путь активной политики к этому файлу. Файл контекста съёмных устройств по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/removable_context +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Файл состоит из следующей однострочной записи: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +.I user role type range +.RS +Пользователь, роль, тип и необязательный диапазон (для MCS/MLS), разделённые двоеточиями (:), которые будут применены к съёмным устройствам. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/removable_contexts +.br +system_u:object_r:removable_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux "(8), " selinux_removable_context_path "(3), " selinux_config "(5) " + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/secolor.conf.5 b/man/ru/man5/secolor.conf.5 new file mode 100644 index 0000000..bcae80c --- /dev/null +++ b/man/ru/man5/secolor.conf.5 @@ -0,0 +1,180 @@ +.TH "secolor.conf" "5" "08 апреля 2011" "Документация API SELinux" +.SH "ИМЯ" +secolor.conf \- файл конфигурации цвета SELinux +. +.SH "ОПИСАНИЕ" +Этот необязательный файл управляет цветом, который назначается компонентам контекста, связанным с контекстом +.I raw +, который передаётся с помощью +.BR selinux_raw_context_to_color "(3)," +когда поддерживающее SELinux приложение должно показать сведения о контексте в цвете. +.sp +.BR selinux_raw_context_to_color "(3)" +получает эту информацию о цвете из файла активной политики +.B secolor.conf +, возвращённого +.BR selinux_colors_path "(3)." +. +.SH "ФОРМАТ ФАЙЛА" +Формат файла: +.RS +.B color +.I color_name +.BI "= #"color_mask +.br +[...] +.sp +.I context_component string +.B = +.I fg_color_name bg_color_name +.br +[...] +.sp +.RE + +Где: +.br +.B color +.RS +Ключевое слово цвета (color). Каждая запись цвета находится на новой строке. +.RE +.I color_name +.RS +Название цвета из одного слова (например, red (красный)). +.RE +.I color_mask +.RS +Маска цвета, начинающаяся с хэша (#), который описывает шестнадцатиричные RGB-цвета, где black (чёрный) #000000 и white (белый) #ffffff. +.RE +.I context_component +.RS +Имя компонента контекста, должно быть одним из следующих: +.br +.RS +пользователь, роль, тип или диапазон +.RE +Каждая запись +.IR context_component " " string " ..." +находится на новой строке. +.RE +.I string +.RS +Это строка +.I context_component +, которая будет сопоставляться с компонентом контекста +.I raw +, который передаётся +.BR selinux_raw_context_to_color "(3)." +.br +Подстановочный знак '*' можно использовать для сопоставления какой-либо неопределённой строки только записям +.I context_component +пользователя, роли или типа. +.RE + +.I fg_color_name +.RS +Строка color_name, которая будет использоваться как цвет переднего плана. Маска цвета +.I color_mask +также может использоваться. +.RE +.I bg_color_name +.RS +Строка color_name, которая будет использоваться как цвет фона. Маска цвета +.I color_mask +также может использоваться. +.RE +. +.SH "ПРИМЕРЫ" +Записи примера 1: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #D2B48C +.sp +user * = black white +.br +role * = white black +.br +type * = tan orange +.br +range s0\-s0:c0.c1023 = black green +.br +range s1\-s1:c0.c1023 = white green +.br +range s3\-s3:c0.c1023 = black tan +.br +range s5\-s5:c0.c1023 = white blue +.br +range s7\-s7:c0.c1023 = black red +.br +range s9\-s9:c0.c1023 = black orange +.br +range s15\-s15:c0.c1023 = black yellow +.RE + +.sp +Записи примера 2: +.RS +color black = #000000 +.br +color green = #008000 +.br +color yellow = #ffff00 +.br +color blue = #0000ff +.br +color white = #ffffff +.br +color red = #ff0000 +.br +color orange = #ffa500 +.br +color tan = #d2b48c +.sp +user unconfined_u = #ff0000 green +.br +role unconfined_r = red #ffffff +.br +type unconfined_t = red orange +.br +user user_u = black green +.br +role user_r = white black +.br +type user_t = tan red +.br +user xguest_u = black yellow +.br +role xguest_r = black red +.br +type xguest_t = black green +.br +user sysadm_u = white black +.br +range s0\-s0:c0.c1023 = black white +.br +user * = black white +.br +role * = black white +.br +type * = black white +.RE +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux "(8), " selinux_raw_context_to_color "(3), " selinux_colors_path "(3)" + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/securetty_types.5 b/man/ru/man5/securetty_types.5 new file mode 100644 index 0000000..ce0aa32 --- /dev/null +++ b/man/ru/man5/securetty_types.5 @@ -0,0 +1,49 @@ +.TH "securetty_types" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +securetty_types \- файл конфигурации типа безопасного терминала (tty) SELinux +. +.SH "ОПИСАНИЕ" +Файл +.I securetty_types +содержит список типов, связанных с типом безопасного tty, которые определены в политике для использования поддерживающими SELinux приложениями. +.sp +.BR selinux_securetty_types_path "(3) " +вернёт путь активной политики к этому файлу. Файл типов securetty по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/securetty_types +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +.BR selinux_check_securetty_context "(3) выполняет чтение этого файла, чтобы определить, установлен ли в активной политике контекст для безопасного tty. " +.sp +Поддерживающие SELinux приложения, такие как +.BR newrole "(1), используют эту информацию для проверки состояния tty. " +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле состоит из следующей записи: +.sp +.RS +.I type +.RS +Одна или несколько записей типов, которые определены в политике для безопасных устройств tty. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/securetty_types +.br +sysadm_tty_device_t +.br +user_tty_device_t +.br +staff_tty_device_t +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selinux_securetty_types_path "(3), " newrole "(1), " selinux_check_securetty_context "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/selabel_db.5 b/man/ru/man5/selabel_db.5 new file mode 100644 index 0000000..1c667e8 --- /dev/null +++ b/man/ru/man5/selabel_db.5 @@ -0,0 +1,219 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: KaiGai Kohei 2009 +.TH "selabel_db" "5" "01 декабря 2011" "Security Enhanced Linux" "Документация API SELinux" +.SH "ИМЯ" +selabel_db \- интерфейс проставления меток SELinux в пространстве пользователя и формат файла конфигурации для внутренней службы контекстов объектов RDBMS (реляционная СУБД) +. +.SH "ОБЗОР" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "ОПИСАНИЕ" +Внутренняя служба контекста базы данных сопоставляет имя и класс объекта с контекстами безопасности. Это действие позволяет найти правильный контекст для объектов базы данных при повторном проставлении меток для определённой базы данных. Необходимо освободить возвращённый \fIcontext\fR с помощью \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) описывает функцию с её возвращаемыми значениями и кодами ошибок. +.sp +\fIobject_name\fR должно быть полным именем, которое использует иерархию объектов базы данных. Например, таблица \fBpg_class\fR в базе данных \fBpostgres\fR и схема \fBpg_catalog\fR должны быть указаны следующим образом: +.RS +.B postgres.pg_catalog.pg_class +.RE +.sp +В разделе \fBПРИМЕЧАНИЯ\fR доступны более подробные сведения о поддержке баз данных для иерархий пространства имён. +.sp +Для аргумента \fIobject_type\fR должно быть установлено одно из следующих значений: +.RS +.TP +.B SELABEL_DB_DATABASE +Аргумент +.I object_name +определяет имя самой базы данных, например, "postgres". +.TP +.B SELABEL_DB_SCHEMA +Аргумент +.I object_name +определяет имя объекта схемы, например, "postgres.public". +.TP +.B SELABEL_DB_TABLE +Аргумент +.I object_name +определяет имя объекта таблицы, например, "postgres.public.my_table" +.TP +.B SELABEL_DB_COLUMN +Аргумент +.I object_name +определяет имя объекта столбца, например, "postgres.public.my_table.user_id" +.TP +.B SELABEL_DB_TUPLE +Аргумент +.I object_name +определяет имя объекта таблицы, содержащей кортежи, для которых требуется повторно проставить метки, например, "postgresql.public.my_table". Следует учитывать, что нет способа идентифицировать отдельные объекты кортежа (за исключением условия WHERE для инструкций DML), потому что у них нет имён. +.TP +.B SELABEL_DB_PROCEDURE +Аргумент +.I object_name +определяет имя объекта процедуры, например, "postgres.public.my_func". Следует учитывать, что поиск отдельных контекстов безопасности для процедур с одинаковыми именами, но разными аргументами не поддерживается. +.TP +.B SELABEL_DB_SEQUENCE +Аргумент +.I object_name +определяет имя объекта последовательности, например, "postgres.public.my_seq". +.TP +.B SELABEL_DB_BLOB +Аргумент +.I object_name +определяет имя большого объекта, например, "postgres.16308". +Следует учитывать, что у большого объекта нет имени, поэтому он идентифицируется по значению соответствующего идентификатора. +.TP +.B SELABEL_DB_VIEW +Аргумент +.I object_name +определяет имя объекта просмотра, например, "postgres.public.my_view". +.TP +.B SELABEL_DB_LANGUAGE +Аргумент +.I object_name +определяет имя объекта языка, например, "postgres.public.tcl". +.TP +.B SELABEL_DB_EXCEPTION +Аргумент +.I object_name +определяет имя объекта исключения. +.TP +.B SELABEL_DB_DATATYPE +Аргумент +.I object_name +определяет имя объекта типа или домена, например, postgres.public.my_type. +.RE +.sp +Все сообщения, созданные с помощью \fBselabel_lookup\fR(3), по умолчанию отправляются в \fIstderr\fR. Это поведение можно изменить с помощью \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +работает аналогично \fBselabel_lookup\fR(3), но не выполняет преобразование контекста. +.sp +В разделе \fBФАЙЛЫ\fR приводится описание файлов конфигурации, которые используются для определения контекста объекта базы данных. +. +.SH "ПАРАМЕТРЫ" +Помимо глобальных параметров, описание которых приведено в \fBselabel_open\fR(3), эта внутренняя служба распознаёт следующие параметры: +.RS +.TP +.B SELABEL_OPT_PATH +Значение этого параметра, отличное от null, определяет путь к файлу, который будет открыт вместо стандартного файла контекста базы данных. +По умолчанию параметр пытается открыть файл спецификации, предназначенный для SE-PostgreSQL; если этот интерфейс используется другой реляционной СУБД, параметр должен явно объявить файл спецификации, предназначенный для такой реляционной СУБД (подробные сведения см. в разделе \fBФАЙЛЫ\fR). +.RE +. +.SH "ФАЙЛЫ" +То, какой файл контекстов базы данных будет использоваться для получения контекста, зависит от параметра \fBSELABEL_OPT_PATH\fR, переданного в \fBselabel_open\fR(3). Если \fINULL\fR, то значением \fBSELABEL_OPT_PATH\fR по умолчанию станет расположение контекстов базы данных активной политики (возвращённое \fBselinux_sepgsql_context_path\fR(3)). В ином случае будет использоваться фактическое указанное значение \fBSELABEL_OPT_PATH\fR (этот вариант необходимо использовать для поддержки баз данных, отличных от SE-PostgreSQL). +.sp +Файл контекстов объекта базы данных по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/sepgsql_context +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +Записи внутри файла контекстов базы данных показаны в разделах \fBЗначения строки имени объекта\fR и \fBФОРМАТ ФАЙЛА\fR. +. +.SH "Значения строки имени объекта" +Имена строк, назначенные аргументам \fIobject_type\fR, которые могут присутствовать в файле контекстов базы данных: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Текстовое имя +SELABEL_DB_DATABASE@db_database +SELABEL_DB_SCHEMA@db_schema +SELABEL_DB_VIEW@db_view +SELABEL_DB_LANGUAGE@db_language +SELABEL_DB_TABLE@db_table +SELABEL_DB_COLUMN@db_column +SELABEL_DB_TUPLE@db_tuple +SELABEL_DB_PROCEDURE@db_procedure +SELABEL_DB_SEQUENCE@db_sequence +SELABEL_DB_BLOB@db_blob +SELABEL_DB_EXCEPTION@db_exception +SELABEL_DB_DATATYPE@db_datatype +.TE +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка внутри файла контекстов базы данных имеет следующий вид: +.RS +.I object_type object_name context +.RE +.sp +Где: +.RS +.I object_type +.RS +Строковое представление типа объекта, показанное в разделе \fBЗначения строки имени объекта\fR. +.RE +.I object_name +.RS +Ключ, который используется для получения контекста на основе \fIobject_type\fR. +.sp +Запись может содержать подстановочные знаки '*' или '?' для выполнения сопоставления с дополнением или подстановкой. +.sp +Следует учитывать, что при использовании '*' важен порядок записей в файле. '*' в отдельном виде используется для того, чтобы обеспечить назначение резервного контекста по умолчанию, это должна быть последняя запись в блоке \fIobject_type\fR. +.RE +.I context +.RS +К объекту будет применён этот контекст безопасности. +.RE +.RE +.sp +Далее приведён пример для SE-PostgreSQL: +.sp +# ./contexts/sepgsql_contexts file +.br +# object_type object_name context +.br +db_database my_database system_u:object_r:sepgsql_db_t:s0 +.br +db_database * system_u:object_r:sepgsql_db_t:s0 +.br +db_schema *.* system_u:object_r:sepgsql_schema_t:s0 +.br +db_tuple row_low system_u:object_r:sepgsql_table_t:s0 +.br +db_tuple row_high system_u:object_r:sepgsql_table_t:s0:c1023 +.br +db_tuple *.*.* system_u:object_r:sepgsql_table_t:s0 +. +.SH "ПРИМЕЧАНИЯ" +.IP "1." 4 +Для целевой реляционной СУБД необходимо записать подходящий файл контекстов базы данных и использовать для его загрузки параметр \fBSELABEL_OPT_PATH\fR в \fBselabel_open\fR(3). +.IP "2." 4 +Иерархия пространства имён для объектов базы данных зависит от реляционной СУБД, но интерфейсы \fIselabel*\fR не предусматривают какой-либо особой поддержки иерархии пространства имён. +.sp +В иерархии пространства имён SE-PostgreSQL объектом верхнего уровня является база данных, объектом следующего уровня - схема. На следующем после объекта схемы уровне могут находиться другие типы объектов, например, таблицы и процедуры. Эта иерархия поддерживается следующим образом: +.RS +.RS +.sp +Если для таблицы "my_table" в схеме "public" +внутри базы данных "postgres" требуется контекст безопасности, то параметрами \fBselabel_lookup\fR(3) +для \fIobject_type\fR будет \fBSELABEL_DB_TABLE\fR, для \fIobject_name\fR - "postgres.public.my_table", контекст безопасности (если доступно) будет возвращён в \fIcontext\fR. +.RE +.RE +.IP "3." 4 +Если контексты должны быть проверены, необходимо указать глобальный параметр \fBSELABEL_OPT_VALIDATE\fR перед вызовом \fBselabel_open\fR(3). Если этот параметр не указан, может быть возвращён недействительный контекст. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_sepgsql_context_path "(3), " freecon "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/selabel_file.5 b/man/ru/man5/selabel_file.5 new file mode 100644 index 0000000..0857b9a --- /dev/null +++ b/man/ru/man5/selabel_file.5 @@ -0,0 +1,219 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_file" "5" "01 декабря 2011" "Security Enhanced Linux" "Документация API SELinux" +.SH "ИМЯ" +selabel_file \- интерфейс проставления меток SELinux в пространстве пользователя и формат файла конфигурации для внутренней службы контекстов файлов +. +.SH "ОБЗОР" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" path ", int " mode ");" +. +.SH "ОПИСАНИЕ" +Внутренняя служба контекстов файлов сопоставляет сочетания 'путь/режим' с контекстами безопасности. Это действие служит для нахождения правильного контекста для каждого файла при повторном проставлении меток в файловой системе. Необходимо освободить возвращённый \fIcontext\fR с помощью \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) описывает функцию с её возвращаемыми значениями и кодами ошибок. Тем не менее, далее приводится более подробное описание следующих значений \fIerrno\fR для внутренней службы контекстов файлов: +.RS +.TP +.B ENOENT +Не найден контекст, соответствующий \fIpath\fR и \fImode\fR, - это сообщение будет возвращено и в том случае, если серия файлов контекстов файлов имеет контекст \fB<>\fR относительно \fIpath\fR (см. раздел \fBФОРМАТ ФАЙЛА\fR). +.RE +.sp +Аргумент \fIpath\fR должен быть установлен в полный путь к файлу, назначенный контекст которого проверяется. Аргумент \fImode\fR должен быть установлен в биты режима файла, как определено \fBlstat\fR(2). Аргумент \fImode\fR может быть нулевым, но в этом случае, возможно, не удастся установить полное соответствие. +.sp +Все сообщения, созданные с помощью \fBselabel_lookup\fR(3), по умолчанию отправляются в \fIstderr\fR. Это поведение можно изменить с помощью \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +работает аналогично \fBselabel_lookup\fR(3), но не выполняет преобразование контекста. +.sp +В разделе \fBФАЙЛЫ\fR приводится описание файлов конфигурации, которые используются для определения контекста файла. +. +.SH "ПАРАМЕТРЫ" +Помимо глобальных параметров, описание которых приведено в +.BR selabel_open (3), +эта внутренняя служба распознаёт следующие параметры: +.RS +.TP +.B SELABEL_OPT_PATH +Значение этого параметра, отличное от null, определяет путь к файлу, который будет открыт вместо стандартного файла контекстов файлов. Это значение также используется как базовое имя для определения имён локальных файлов настройки. +.TP +.B SELABEL_OPT_BASEONLY +Отличное от null значение этого параметра означает, что любую локальную настройку сопоставления контекста файла следует игнорировать. +.TP +.B SELABEL_OPT_SUBSET +Отличное от null значение этого параметра интерпретируется как префикс пути, например, "/etc". Будут загружены только те спецификации контекстов файлов, первый компонент которых совпадает с указанным префиксом. Это может ускорить выполнение поиска, но, возможно, не удастся найти путь, который не начинается с указанного префикса. Данная оптимизация поиска больше не требуется (и устарела), вместо неё используется +.I file_contexts.bin. +.RE +. +.SH "ФАЙЛЫ" +То, какие файлы контекстов файлов используются для получения контекста по умолчанию, зависит от параметра \fBSELABEL_OPT_PATH\fR, переданного в \fBselabel_open\fR(3). Если это \fINULL\fR, то \fBSELABEL_OPT_PATH\fR по умолчанию примет значение расположения контекстов файлов активной политики (которое возвращает \fBselinux_file_context_path\fR(3)), в ином случае будет использовано фактическое указанное значение \fBSELABEL_OPT_PATH\fR. +.sp +Если параметр \fBSELABEL_OPT_BASEONLY\fR задан, будут обрабатываться следующие файлы: +.RS +.IP "1." 4 +Обязательный файл контекстов файлов - это либо полное имя файла из \fISELABEL_OPT_PATH.value\fR, либо (если \fINULL\fR) путь, который возвращает \fBselinux_file_context_path\fR(3). +.IP "2." 4 +Необязательные файлы для замены имён (файл для локального использования и файл для использования с дистрибутивами), которые присваивают псевдонимы пути для 'находящейся в памяти' версии файла контекстов файлов. +.br +Эти файлы имеют то же имя, что и у обязательного файла контекстов файлов, и расширения \fI.subs\fR и \fI.subs_dist\fR. +.RE +.sp +Если параметр \fBSELABEL_OPT_BASEONLY\fR не задан, будут обработаны следующие файлы: +.RS +.IP "1." 4 +Обязательный файл контекстов файлов, который является либо полным именем файла из \fISELABEL_OPT_PATH.value\fR, либо (если \fINULL\fR) путём, который возвращает \fBselinux_file_context_path\fR(3). +.IP "2." 4 +Необязательный файл локальной настройки, имеющий то же имя, что и обязательный файл контекстов файлов, и расширение \fI.local\fR. +.br +\fBselinux_file_context_local_path\fR(3) вернёт путь по умолчанию к этому файлу. +.IP "3." 4 +Необязательный файл настройки домашнего каталога пользователя, имеющий то же имя, что и обязательный файл контекстов файлов, и расширение \fI.homedirs\fR. +.br +\fBselinux_file_context_homedir_path\fR(3) вернёт путь по умолчанию к этому файлу. +.IP "4." 4 +Необязательные файлы для замены имён (файл для локального использования и файл для использования с дистрибутивами), которые присваивают псевдонимы пути для 'находящейся в памяти' версии файла контекстов файлов (и \fI.local\fR и/или \fI.homedirs\fR, если они имеются). Эти файлы имеют то же имя, что и обязательный файл контекстов файлов, и расширения \fI.subs\fR и \fI.subs_dist\fR. +.br +\fBselinux_file_context_subs_path\fR(3) и \fBselinux_file_context_subs_dist_path\fR(3) вернут пути по умолчанию к этим файлам. +.RE +.sp +По умолчанию серия файлов контекстов файлов: +.RS 6 +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.local +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.homedirs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.subs_dist +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +Обязательным является только файл \fIfile_contexts\fR, все остальные являются необязательными. +.sp +Записи внутри серии файлов контекстов файлов показаны в разделе \fBФОРМАТ ФАЙЛА\fR. +. +.SH "ФОРМАТ ФАЙЛА" +.sp +.SH "Формат контекстов файлов" +.sp +Каждая строка внутри \fIfile_contexts\fR и двух файлов настройки (\fI.local\fR и \fI.homedirs\fR) имеет следующий вид: +.sp +.RS +.I pathname [file_type] context +.RE +.sp +Где: +.br +.RS +.I pathname +.RS +Определяющая имя пути запись, которая может быть в виде регулярного выражения. +.RE +.I file_type +.RS +Необязательный тип файла, который состоит из: +.RS +\fI\-b\fR - устройство блочного ввода-вывода \fI\-c\fR - устройство символьного ввода-вывода +.br +\fI\-d\fR - каталог \fI\-p\fR - именованный канал +.br +\fI\-l\fR - символическая ссылка \fI\-s\fR - сокет +.br +\fI\-\-\fR - обычный файл +.RE +.RE +.I context +.RS +Запись может быть одним из следующих: +.RS +.IP "a." 4 +Контекст безопасности, который будет назначен этому файлу (то есть возвращён как \fIcontext\fR). +.IP "b." 4 +Значение \fB<>\fR можно использовать, чтобы указать, что для соответствующих файлов не следует повторно проставлять метки, а также при этом значении \fBselabel_lookup\fR(3) вернёт \-1 при установке \fIerrno\fR в \fBENOENT\fR. +.RE +.RE +.RE +.sp +Пример: +.RS +# ./contexts/files/file_contexts +.br +# pathname file_type context +.br +/.* system_u:object_r:default_t:s0 +.br +/[^/]+ \-\- system_u:object_r:etc_runtime_t:s0 +.br +/tmp/.* <> +.RE +.sp +.SH "Формат файла подстановки" +.sp +Каждая строка внутри файлов подстановки (\fI.subs\fR и \fI.subs_dist\fR) имеет вид: +.RS +.I subs_pathname pathname +.RE +.sp +Где: +.RS +.I pathname +.RS +Путь, который соответствует записи в одном или нескольких файлах конфигурации политики контекстов файлов. +.RE +.I subs_pathname +.RS +Путь, который станет псевдонимом имени пути (считается равнозначным при поиске). +.RE +.RE +.sp +Пример: +.RS +# ./contexts/files/file_contexts.subs +.br +# pathname subs_pathname +.br +/myweb /var/www +.br +/myspool /var/spool/mail +.sp +Пример выше: когда в \fBselabel_lookup\fR(3) передаётся путь \fI/myweb/index.html\fR, функция заменяет компонент \fI/myweb\fR +на \fI/var/www\fR, поэтому будет использоваться следующий путь: +.sp +.RS +.I /var/www/index.html +.RE +.RE +. +.SH "ПРИМЕЧАНИЯ" +.IP "1." 4 +Если контексты должны быть проверены, необходимо указать глобальный параметр \fBSELABEL_OPT_VALIDATE\fR перед вызовом \fBselabel_open\fR(3). Если этот параметр не указан, может быть возвращён недействительный контекст. +.IP "2." 4 +Если серия файлов контекстов файлов содержит много записей, \fBselabel_open\fR(3) может медленно выполнять чтение в файлах и (если это запрошено) проверку записей. +.IP "3." 4 +В некоторых версиях SELinux также может присутствовать файл \fIfile_contexts.template\fR, но он устарел. +.br +Файл шаблона имеет тот же формат, что и файл \fIfile_contexts\fR, а также может содержать ключевые слова \fBHOME_ROOT\fR, \fBHOME_DIR\fR, \fBROLE\fR и \fBUSER\fR. Эта функциональность была перемещена в хранилище политик и управляется \fBsemodule\fR(8) и \fBgenhomedircon\fR(8). +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_file_context_path "(3), " freecon "(3), " selinux_config "(5), " lstat "(2), "selinux_file_context_subs_path "(3), " selinux_file_context_subs_dist_path "(3), " selinux_file_context_homedir_path "(3), "selinux_file_context_local_path "(3), " semodule "(8), " genhomedircon "(8) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/selabel_media.5 b/man/ru/man5/selabel_media.5 new file mode 100644 index 0000000..9fec7b0 --- /dev/null +++ b/man/ru/man5/selabel_media.5 @@ -0,0 +1,92 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_media" "5" "29 ноября 2011" "Security Enhanced Linux" "Документация API SELinux" +.SH "ИМЯ" +selabel_media \- интерфейс проставления меток SELinux в пространстве пользователя и формат файла конфигурации для внутренней службы контекстов носителей +. +.SH "ОБЗОР" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" device_name ", int " unused ");" +. +.SH "ОПИСАНИЕ" +Внутренняя служба контекстов носителей сопоставляет имена устройств мультимедиа, например, "cdrom" или "floppy", с контекстами безопасности. Это действие служит для нахождения правильного контекста для установки контекстных подключений к этим устройствам. Необходимо освободить возвращённый \fIcontext\fR с помощью \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) описывает функцию с её возвращаемыми значениями и кодами ошибок. +.sp +Аргумент поиска целого числа в настоящее время не используется, для него следует указать равное нулю значение. +.sp +Все сообщения, созданные с помощью \fBselabel_lookup\fR(3), по умолчанию отправляются в \fIstderr\fR. Это поведение можно изменить с помощью \fBselinux_set_callback\fR(3). +.sp +.BR selabel_lookup_raw (3) +работает аналогично \fBselabel_lookup\fR(3), но не выполняет преобразование контекста. +.sp +В разделе \fBФАЙЛЫ\fR приводится описание файлов конфигурации, которые используются для определения контекстов носителей. +. +.SH "ПАРАМЕТРЫ" +Помимо глобальных параметров, описание которых приведено в \fBselabel_open\fR(3), эта внутренняя служба распознаёт следующие параметры: +.TP +.B SELABEL_OPT_PATH +Значение этого параметра, отличное от null, определяет путь к файлу, который будет открыт вместо стандартного файла контекстов носителей \fImedia\fR. +. +.SH "ФАЙЛЫ" +То, какой файл контекстов носителей будет использоваться для получения контекста по умолчанию, зависит от параметра \fBSELABEL_OPT_PATH\fR, переданного в \fBselabel_open\FR(3). Если это \fINULL\fR, то значением \fBSELABEL_OPT_PATH\fR по умолчанию станет расположение контекстов носителей активной политики (возвращённое \fBselinux_media_context_path\fR(3)). В ином случае будет использовано фактическое указанное значение \fBSELABEL_OPT_PATH\fR. +.sp +Файл контекстов носителей по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/files/media +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка внутри файла \fImedia\fR имеет следующий вид: +.RS +.I device_name context +.RE +.sp +Где: +.RS +.I device_name +.RS +Идентификатор носителя (например, cdrom, floppy, disk и usb). +.RE +.I context +.RS +Контекст, который следует использовать для проставления метки устройства. +.RE +.RE +.sp +Пример: +.RS +# contexts/files/media +.br +cdrom system_u:object_r:removable_device_t +.br +floppy system_u:object_r:removable_device_t +.br +disk system_u:object_r:fixed_disk_device_t +. +.SH "ПРИМЕЧАНИЯ" +Если контексты должны быть проверены, необходимо указать глобальный параметр \fBSELABEL_OPT_VALIDATE\fR перед вызовом \fBselabel_open\fR(3). Если этот параметр не указан, может быть возвращён недействительный контекст. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_media_context_path "(3), " freecon "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/selabel_x.5 b/man/ru/man5/selabel_x.5 new file mode 100644 index 0000000..969ce1e --- /dev/null +++ b/man/ru/man5/selabel_x.5 @@ -0,0 +1,168 @@ +.\" Hey Emacs! This file is -*- nroff -*- source. +.\" +.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007 +.TH "selabel_x" "5" "29 ноября 2011" "Security Enhanced Linux" "Документация API SELinux" +.SH "ИМЯ" +selabel_x \- интерфейс проставления меток SELinux в пространстве пользователя и формат файла конфигурации для внутренней службы контекстов оконной системы X Window System. Эта внутренняя служба также используется для определения контекста по умолчанию, который следует присвоить подключённым удалённо клиентам X +. +.SH "ОБЗОР" +.B #include +.sp +.BI "int selabel_lookup(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +.in +.sp +.BI "int selabel_lookup_raw(struct selabel_handle *" hnd , +.in +\w'int selabel_lookup('u +.BI "char **" context , +.br +.BI "const char *" object_name ", int " object_type ");" +. +.SH "ОПИСАНИЕ" +Внутренняя служба контекстов X сопоставляет имена объектов X Window System с контекстами безопасности. Это действие служит для нахождения правильного контекста для объектов X Window System, значимость и/или семантика использования которых в основном определяются именем. Необходимо освободить возвращённый \fIcontext\fR с помощью \fBfreecon\fR(3). +.br +\fBselabel_lookup\fR(3) описывает функцию с её возвращаемыми значениями и кодами ошибок. +.sp +Эта внутренняя служба также используется для определения контекста по умолчанию, который следует назначить для подключённых удалённо клиентов X. +.sp +Для аргумента \fIobject_type\fR необходимо установить одно из следующих значений: +.RS +.TP +.B SELABEL_X_PROP +Аргумент +.I object_name +указывает имя свойства окна, например, "WM_NAME". +.TP +.B SELABEL_X_SELN +Аргумент +.I object_name +указывает имя выделения, например, "PRIMARY". +.TP +.B SELABEL_X_EXT +Аргумент +.I object_name +указывает имя расширения протокола, например, "RENDER". +.TP +.B SELABEL_X_EVENT +Аргумент +.I object_name +указывает имя типа события, например, "X11:ButtonPress". +.TP +.B SELABEL_X_CLIENT +Аргумент +.I object_name +игнорируется, но его значением необходимо установить либо \fI*\fR (звёздочка, 'подстановочный знак': будет выбрана запись по умолчанию), либо конкретную запись, такую как "remote" в файле контекстов X, как показано в разделе \fBПРИМЕР\fR. В этом случае будет возвращён контекст по умолчанию, который следует присвоить удалённым клиентам X. +.TP +.B SELABEL_X_POLYPROP +Работает аналогично +.BR SELABEL_X_PROP , +но проверяет, было ли свойство отмечено как многоэкземплярное. См. \fBПРИМЕЧАНИЯ\fR далее. +.TP +.B SELABEL_X_POLYSELN +Аналогично +.BR SELABEL_X_SELN , +но проверяет, было ли выделение отмечено как многоэкземплярное. См. \fBПРИМЕЧАНИЯ\fR далее. +.RE +.sp +Все сообщения, созданные \fBselabel_lookup\fR(3), по умолчанию отправляются в \fIstderr\fR. Это поведение можно изменить с помощью \fBselinux_set_callback\fR(3). +.sp +.B selabel_lookup_raw +работает аналогично \fBselabel_lookup\fR, но не выполняет преобразование контекста. +.sp +В разделе \fBФАЙЛЫ\fR приводится описание файлов конфигурации, которые используются для определения контекстов объектов Х. +. +.SH "ПАРАМЕТРЫ" +Помимо глобальных параметров, описание которых приведено в \fBselabel_open\fR(3), эта внутренняя служба распознаёт следующие параметры: +.RS +.TP +.B SELABEL_OPT_PATH +Значение этого параметра, отличное от null, определяет путь к файлу, который будет открыт вместо стандартного файла контекстов Х (подробные сведения см. в разделе \fBФАЙЛЫ\fR). +.RE +. +.SH "ФАЙЛЫ" +То, какой файл контекста Х будет использоваться для получения контекста по умолчанию, зависит от параметра \fBSELABEL_OPT_PATH\fR, переданного в \fBselabel_open\fR(3). Если \fINULL\fR, то значением \fBSELABEL_OPT_PATH\fR по умолчанию станет расположение контекстов Х активной политики (возвращённое \fBselinux_x_context_path\fR(3)). В ином случае будет использовано фактическое указанное значение \fBSELABEL_OPT_PATH\fR. +.sp +Файл контекстов объектов Х по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/x_contexts +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +Записи, находящиеся внутри файла контекстов X, показаны в разделах \fBЗначения строки имени объекта\fR и \fBФОРМАТ ФАЙЛА\fR. +. +.SH "Значения строки имени объекта" +Имена строк, назначенные аргументам \fIobject_type\fR, которые могут присутствовать в файле контекстов X: +.TS +center, allbox, tab(@); +lI lB +lB l . +object_type@Текстовое имя +SELABEL_X_PROP@property +SELABEL_X_SELN@selection +SELABEL_X_EXT@extension +SELABEL_X_EVENT@event +SELABEL_X_CLIENT@client +SELABEL_X_POLYPROP@poly_property +SELABEL_X_POLYSELN@poly_selection +.TE +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка внутри файла контекстов X имеет следующий вид: +.RS +.I object_type object_name context +.RE +.sp +Где: +.RS +.I object_type +.RS +Это строковое представление типа объекта, показанное в разделе \fBЗначения строки имени объекта\fR. +Несколько строк с одной и той же строкой \fIobject_type\fR сформируют блок записей (каждая со своей строкой \fIobject_name\fR). +.RE +.I object_name +.RS +Это имена объектов конкретного ресурса сервера X, например, +\fBPRIMARY\fR, \fBCUT_BUFFER0\fR и т.д. Обычно они определены в исходном коде сервера X (\fIprotocol.txt\fR и \fIBuiltInAtoms\fR в каталоге +dix исходного пакета xorg\-server). +Запись может содержать подстановочные знаки '*' или '?' для выполнения сопоставления с дополнением или подстановкой. +Следует учитывать, что при использовании '*' важен порядок записей в файле. '*' в отдельном виде используется для того, чтобы обеспечить назначение резервного контекста по умолчанию, это должна быть последняя запись в блоке \fIobject_type\fR. +.RE +.I context +.RS +Контекст безопасности, который будет применён к объекту. +.RE +.RE +.sp +Пример 1: +.sp +.nf +# object_type object_name context +selection PRIMARY system_u:object_r:clipboard_xselection_t:s0 +selection * system_u:object_r:xselection_t:s0 +.fi +.sp +Пример 2 - этот пример показывает, как можно настроить запись клиента таким образом, чтобы она всегда находилась: +.sp +.nf +# object_type object_name context +client * system_u:object_r:remote_t:s0 +.fi +. +.SH "ПРИМЕЧАНИЯ" +.IP "1." 4 +Свойства и выделения отмечаются как многоэкземплярные или нет. Для этих типов имён параметр "POLY" выполняет поиск только имён, которые отмечены как многоэкземплярные, в то время как другой параметр выполняет поиск только имён, которые отмечены как не многоэкземплярные. Пользователям этого интерфейса следует проверить оба сопоставления и затем (необязательно) действовать на основе полученного результата (например, сделать объект многоэкземплярным). +.IP "2." 4 +Если контексты должны быть проверены, необходимо указать глобальный параметр \fBSELABEL_OPT_VALIDATE\fR перед вызовом \fBselabel_open\fR(3). Если этот параметр не указан, может быть возвращён недействительный контекст. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selabel_open "(3), " selabel_lookup "(3), " selabel_stats "(3), " selabel_close "(3), " selinux_set_callback "(3), " selinux_x_context_path "(3), " freecon "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/sepgsql_contexts.5 b/man/ru/man5/sepgsql_contexts.5 new file mode 100644 index 0000000..ec2bb47 --- /dev/null +++ b/man/ru/man5/sepgsql_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_db.5 diff --git a/man/ru/man5/service_seusers.5 b/man/ru/man5/service_seusers.5 new file mode 100644 index 0000000..fe57ed6 --- /dev/null +++ b/man/ru/man5/service_seusers.5 @@ -0,0 +1,71 @@ +.TH "service_seusers" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +service_seusers \- файлы конфигурации сопоставления пользователей и служб GNU/Linux с пользователями SELinux +. +.SH "ОПИСАНИЕ" +Это необязательные файлы, которые позволяют службам определять пользователя SELinux при аутентификации через поддерживающие SELinux приложения для входа, например, +.BR PAM "(8). " +.sp +Для каждого имени пользователя GNU/Linux имеется один файл, который потребуется для запуска службы с определённым именем пользователя SELinux. +.sp +Путь к каждому файлу конфигурации формируется путём, который был возвращён +.BR selinux_policy_root "(3), с добавлением " +.IR /logins/username +в конце (где \fIusername\fR - это файл, представляющий имя пользователя GNU/Linux). Каталог служб по умолчанию расположен по следующему адресу: +.RS +.I /etc/selinux/{SELINUXTYPE}/logins +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +.BR getseuser "(3) выполняет чтение этого файла для сопоставления служб с пользователем SELinux. " +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка внутри файла \fIusername\fR имеет следующий формат, каждый компонент отделяется двоеточием: +.RS +.IB service : seuser \fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +.I service +.RS +Имя службы, которая используется приложением. +.RE +.I seuser +.RS +Имя пользователя SELinux. +.RE +.I range +.RS +Диапазон для политики MCS/MLS. +.RE +.RE +. +.SH "ПРИМЕРЫ" +Пример 1 - для пользователя 'root': +.RS +# ./logins/root +.br +ipa:user_u:s0 +.br +this_service:unconfined_u:s0 +.RE +.sp +Пример 2 - для пользователя GNU/Linux 'rch': +.RS +# ./logins/rch +.br +ipa:unconfined_u:s0 +.br +that_service:unconfined_u:s0 +.RE +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_policy_root "(3), " getseuser "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/seusers.5 b/man/ru/man5/seusers.5 new file mode 100644 index 0000000..f829653 --- /dev/null +++ b/man/ru/man5/seusers.5 @@ -0,0 +1,67 @@ +.TH "seusers" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +seusers \- файл конфигурации сопоставления пользователей GNU/Linux с пользователями SELinux +. +.SH "ОПИСАНИЕ" +Файл +.I seusers +содержит список сопоставления пользователей GNU/Linux с пользователями SELinux, который используется поддерживающими SELinux приложениями для входа, например, \fBPAM\fR(8). +.sp +.BR selinux_usersconf_path "(3) " +вернёт путь активной политики к этому файлу. Файл сопоставления пользователей SELinux по умолчанию находится по следующему адресу: +.RS +.I /etc/selinux/{SELINUXTYPE}/seusers +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +.BR getseuserbyname "(3) выполняет чтение этого файла для сопоставления пользователя или группы GNU/Linux с пользователем SELinux. " +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка файла конфигурации +.I seusers +состоит из следующих компонентов: +.sp +.RS +\fR[\fB%\fIgroup_id\fR]|[\fIuser_id\fR]\fB:\fIseuser_id\fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +\fIgroup_id\fR|\fIuser_id +.RS +\fRИдентификатор пользователя GNU/Linux или (если предваряется символом процентного значения (\fB%\fR)) идентификатор группы GNU/Linux. +.br +При необходимости в качестве резервной записи можно предоставить необязательную запись, установленную в \fB__default__\fR. +.RE +.I seuser_id +.RS +Идентификатор пользователя SELinux. +.RE +.I range +.RS +Необязательный уровень или диапазон для политики MLS/MCS. +.RE +.RE +. +.SH "ПРИМЕР" +# ./seusers +.br +system_u:system_u:s0\-s15:c0.c255 +.br +root:root:s0\-s15:c0.c255 +.br +fred:user_u:s0 +.br +__default__:user_u:s0 +.br +%user_group:user_u:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " PAM "(8), " selinux_usersconf_path "(3), " getseuserbyname "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/user_contexts.5 b/man/ru/man5/user_contexts.5 new file mode 100644 index 0000000..de3a8bd --- /dev/null +++ b/man/ru/man5/user_contexts.5 @@ -0,0 +1,85 @@ +.TH "user_contexts" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +user_contexts \- файлы конфигурации SELinux-контекстов пользователей SELinux +. +.SH "ОПИСАНИЕ" +Эти необязательные файлы конфигурации контекстов пользователей содержат записи, которые позволяют поддерживающим SELinux приложениям для входа, например, +.BR PAM (8) +(запущенным в своих собственных контекстах процессов), определять контекст, в котором должен запускаться сеанс пользователя. +.sp +Обычно поддерживающие SELinux приложения для входа используют одну или несколько следующих функций libselinux, которые выполняют чтение этих файлов по пути активной политики: +.RS +.BR get_default_context (3) +.br +.BR get_ordered_context_list (3) +.br +.BR get_ordered_context_list_with_level (3) +.br +.BR get_default_context_with_level (3) +.br +.BR get_default_context_with_role (3) +.br +.BR get_default_context_with_rolelevel (3) +.br +.BR query_user_context (3) +.br +.BR manual_user_enter_context (3) +.RE +.sp +Для каждого пользователя SELinux можно настроить только один файл. Путь к файлу формируется с помощью пути, возвращённого +.BR \%selinux_user_contexts_path (3) +для активной политики, с добавлением в конце имени пользователя SELinux, например: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/users/unconfined_u +.br +.I /etc/selinux/{SELINUXTYPE}/contexts/users/xguest_u +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +.sp +Эти файлы содержат информацию о контексте в соответствии с описанием в разделе +.B ФОРМАТ ФАЙЛА. +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле конфигурации контекста пользователя состоит из следующих компонентов: +.RS +.I login_process user_login_process +.RE +.sp +Где: +.RS +.I login_process +.RS +Состоит из записи \fIrole\fB:\fItype\fR[\fB:\fIrange\fR], которая представляет собой контекст процесса входа. +.RE +.I user_login_process +.RS +Состоит из записи \fIrole\fB:\fItype\fR[\fB:\fIrange\fR], которая представляет собой контекст процесса входа пользователя. +.RE +.RE +. +.SH "ПРИМЕР" +# Пример для xguest_u в /etc/selinux/targeted/contexts/users/xguest_u +.br +system_r:crond_t:s0 xguest_r:xguest_t:s0 +.br +system_r:initrc_t:s0 xguest_r:xguest_t:s0 +.br +system_r:local_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:remote_login_t:s0 xguest_r:xguest_t:s0 +.br +system_r:sshd_t:s0 xguest_r:xguest_t:s0 +.br +system_r:xdm_t:s0 xguest_r:xguest_t:s0 +.br +xguest_r:xguest_t:s0 xguest_r:xguest_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " selinux_user_contexts_path "(3), " PAM "(8), " get_ordered_context_list "(3), " get_ordered_context_list_with_level "(3), " get_default_context_with_level "(3), " get_default_context_with_role "(3), " get_default_context_with_rolelevel "(3), " query_user_context "(3), " manual_user_enter_context "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/virtual_domain_context.5 b/man/ru/man5/virtual_domain_context.5 new file mode 100644 index 0000000..617eeec --- /dev/null +++ b/man/ru/man5/virtual_domain_context.5 @@ -0,0 +1,44 @@ +.TH "virtual_domain_context" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +virtual_domain_context \- файл конфигурации SELinux-контекста домена виртуальной машины +. +.SH "ОПИСАНИЕ" +Файл +.I virtual_domain_context +содержит список контекстов доменов, которые доступны для использования поддерживающему SELinux API виртуализации libvirt (см. \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_domain_context_path "(3) " +вернёт путь активной политики к этому файлу. Файл контекстов виртуальных доменов по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_domain_context +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле состоит из записи следующего вида: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +.I user role type range +.RS +Пользователь, роль, тип и необязательный диапазон (для MCS/MLS), разделённые двоеточиями (:), которые могут использоваться в качестве контекста виртуального домена. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/virtual_domain_context +.br +system_u:object_r:svirt_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_domain_context_path "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/virtual_image_context.5 b/man/ru/man5/virtual_image_context.5 new file mode 100644 index 0000000..560229f --- /dev/null +++ b/man/ru/man5/virtual_image_context.5 @@ -0,0 +1,46 @@ +.TH "virtual_image_context" "5" "28 ноября 2011" "Security Enhanced Linux" "Конфигурация SELinux" +.SH "ИМЯ" +virtual_image_context \- файл конфигурации SELinux-контекста образа виртуальной машины +. +.SH "ОПИСАНИЕ" +Файл +.I virtual_image_context +содержит список контекстов образов для использования поддерживающим SELinux API виртуализации libvirt (см. \fBlibvirtd\fR(8)). +.sp +.BR selinux_virtual_image_context_path "(3) " +вернёт путь активной политики к этому файлу. Файл контекстов виртуальных образов по умолчанию: +.RS +.I /etc/selinux/{SELINUXTYPE}/contexts/virtual_image_context +.RE +.sp +Где \fI{SELINUXTYPE}\fR - запись из файла конфигурации selinux \fIconfig\fR (см. \fBselinux_config\fR(5)). +. +.SH "ФОРМАТ ФАЙЛА" +Каждая строка в файле состоит из записи следующего вида: +.RS +.IB user : role : type \fR[\fB:\fIrange\fR] +.RE +.sp +Где: +.RS +.I user role type range +.RS +Пользователь, роль, тип и необязательный диапазон (для MCS/MLS), разделённые двоеточиями (:), которые могут использоваться в качестве контекста виртуального образа. +.RE +.RE +. +.SH "ПРИМЕР" +# ./contexts/virtual_image_context +.br +system_u:object_r:svirt_image_t:s0 +.br +system_u:object_r:svirt_content_t:s0 +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR selinux "(8), " libvirtd "(8), " selinux_virtual_image_context_path "(3), " selinux_config "(5) " + + +.SH АВТОРЫ +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man5/x_contexts.5 b/man/ru/man5/x_contexts.5 new file mode 100644 index 0000000..3796d2a --- /dev/null +++ b/man/ru/man5/x_contexts.5 @@ -0,0 +1 @@ +.so man5/selabel_x.5 diff --git a/man/ru/man8/avcstat.8 b/man/ru/man8/avcstat.8 new file mode 100644 index 0000000..b6d8496 --- /dev/null +++ b/man/ru/man8/avcstat.8 @@ -0,0 +1,35 @@ +.TH "avcstat" "8" "18 ноября 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +avcstat \- показать статистику AVC (Access Vector Cache, кэш вектора доступа) SELinux +. +.SH "ОБЗОР" +.B avcstat +.RB [ \-c ] +.RB [ \-f +.IR status_file ] +.RI [ interval ] +. +.SH "ОПИСАНИЕ" +Показать статистику AVC SELinux. Если указан параметр +.I interval +, программа будет выполняться циклами, показывая обновлённую статистику каждые +.I interval +секунд. +По умолчанию показываются относительные значения. +. +.SH ПАРАМЕТРЫ +.TP +.B \-c +Показать совокупные значения. +.TP +.B \-f +Указывает расположение файла статистики AVC, по умолчанию это +.IR /sys/fs/selinux/avc/cache_stats . +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8) +. +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Программа была написана James Morris . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/booleans.8 b/man/ru/man8/booleans.8 new file mode 100644 index 0000000..20e5b00 --- /dev/null +++ b/man/ru/man8/booleans.8 @@ -0,0 +1,46 @@ +.TH "booleans" "8" "11 августа 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +booleans \- логические переключатели политики позволяют настраивать политику SELinux в среде выполнения +. +.SH "ОПИСАНИЕ" +Эта страница руководства описывает логические переключатели политики SELinux. +.BR +Политика SELinux может включать условные правила, которое включены или отключены в зависимости от текущих значений набора логических переключателей политики. +Эти логические переключатели политики позволяют изменять политику безопасности в среде выполнения без загрузки новой политики. + +Например, логический переключатель httpd_enable_cgi (если он включён) позволяет управляющей программе httpd запускать сценарии cgi. Если администратору требуется запретить исполнение сценариев cgi, можно просто установить соответствующее значение этого переключателя. + +Политика определяет значение по умолчанию для каждого логического переключателя, обычно это false. +Эти значения по умолчанию можно переопределить через локальные параметры, созданные с помощью утилиты +.BR setsebool (8) +, используя +.B \-P +для сохранения параметра после перезагрузок. Средство +.B system\-config\-securitylevel +предоставляет графический интерфейс для изменения параметров. Программа +.BR load_policy (8) +по умолчанию сохранит текущие параметры логических переключателей после перезагрузки политики по умолчанию. При необходимости также можно сбросить значения логических переключателей на их значения по умолчанию при загрузке, для этого используется параметр +.B \-b. + +Для получения и вывода списка логических значений служит утилита +.BR getsebool (8) +с параметром +.B \-a. + +Логические значения также можно изменить во время выполнения с помощью утилиты +.BR setsebool (8) +или утилиты +.BR togglesebool (8). +По умолчанию эти утилиты изменяют только текущее логическое значение и не влияют на постоянные параметры, если в setsebool не используется параметр +.B \-P. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR getsebool (8), +.BR setsebool (8), +.BR selinux (8), +.BR togglesebool (8) +. +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Поддержка условной политики SELinux была разработана Tresys Technology. +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/getenforce.8 b/man/ru/man8/getenforce.8 new file mode 100644 index 0000000..13589e1 --- /dev/null +++ b/man/ru/man8/getenforce.8 @@ -0,0 +1,19 @@ +.TH "getenforce" "8" "7 апреля 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +getenforce \- получить текущий режим SELinux +. +.SH "ОБЗОР" +.B getenforce +. +.SH "ОПИСАНИЕ" +.B getenforce +сообщает, в каком режиме работает SELinux (принудительный, разрешительный, отключённый). +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR setenforce (8), +.BR selinuxenabled (8) +. +.SH АВТОРЫ +Dan Walsh, . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/getsebool.8 b/man/ru/man8/getsebool.8 new file mode 100644 index 0000000..04d9820 --- /dev/null +++ b/man/ru/man8/getsebool.8 @@ -0,0 +1,40 @@ +.TH "getsebool" "8" "11 августа 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +getsebool \- получить логические значения SELinux +. +.SH "ОБЗОР" +.B getsebool +.RB [ \-a ] +.RI [ boolean ] +. +.SH "ОПИСАНИЕ" +.B getsebool +сообщает, где включён или отключён конкретный логический переключатель +или все логические переключатели SELinux. +В некоторых ситуациях для логического переключателя может существовать +ожидающее изменение (переход из одного состояние в другое) - getsebool +сообщит об этом. +Ожидающее значение - то значение, которое будет применено при +следующей фиксации логического переключателя. + +Установка значений логических переключателей выполняется в два этапа; +сначала изменяется ожидающее значение, а затем логические переключатели +фиксируются, в результате чего их активные значения заменяются +ожидающими значениями. Это позволяет изменить группу логических +переключателей за одну транзацию, задав все необходимые ожидающие +значения и затем одновременно зафиксировав их. +. +.SH ПАРАМЕТРЫ +.TP +.B \-a +Показать все логические переключатели SELinux. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR setsebool (8), +.BR booleans (8) +. +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Программа была написана Tresys Technology. +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/matchpathcon.8 b/man/ru/man8/matchpathcon.8 new file mode 100644 index 0000000..5bd586d --- /dev/null +++ b/man/ru/man8/matchpathcon.8 @@ -0,0 +1,62 @@ +.TH "matchpathcon" "8" "21 апреля 2005" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +matchpathcon \- получить текущий контекст безопасности SELinux для указанного пути из конфигурации контекстов файлов +. +.SH "ОБЗОР" +.B matchpathcon +.RB [ \-V ] +.RB [ \-N ] +.RB [ \-n ] +.RB [ \-m +.IR type ] +.RB [ \-f +.IR file_contexts_file ] +.RB [ \-p +.IR prefix ] +.RB [ \-P +.IR policy_root_path ] +.I filepath... +. +.SH "ОПИСАНИЕ" +.BR matchpathcon +опрашивает системную политику и выводит контекст безопасности по умолчанию, связанный с путём к файлу. + +.B Примечание: +Одинаковые пути могут иметь разные контексты безопасности в зависимости от типа файла (обычный файл, каталог, файл связи, файл знаков ...). + +.B matchpathcon +также будет учитывать тип файла при определении контекста безопасности по умолчанию (если файл существует). Если файл не существует, сопоставление по типу файла не будет выполнено. +. +.SH ПАРАМЕТРЫ +.TP +.BI \-m " type" +Принудительно указать тип файла для поиска. +Действительные типы: +.BR file ", " dir ", "pipe ", " chr_file ", " blk_file ", " +.BR lnk_file ", " sock_file . +.TP +.B \-n +Не показывать путь. +.TP +.B \-N +Не использовать преобразования. +.TP +.BI \-f " file_context_file" +Использовать альтернативный файл file_context +.TP +.BI \-p " prefix" +Использовать префикс для ускорения преобразований +.TP +.BI \-P " policy_root_path" +Использовать альтернативный корневой путь к политике +.TP +.B \-V +Проверить контекст файла на диске на соответствие параметрам по умолчанию +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux "(8), " +.BR matchpathcon (3) +. +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/sefcontext_compile.8 b/man/ru/man8/sefcontext_compile.8 new file mode 100644 index 0000000..3a6b832 --- /dev/null +++ b/man/ru/man8/sefcontext_compile.8 @@ -0,0 +1,70 @@ +.TH "sefcontext_compile" "8" "12 августа 2015" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +sefcontext_compile \- скомпилировать файлы регулярных выражений контекстов файлов +. +.SH "ОБЗОР" +.B sefcontext_compile +.RB [ \-o +.IR outputfile ] +.RB [ \-p +.IR policyfile ] +.I inputfile +. +.SH "ОПИСАНИЕ" +.B sefcontext_compile +используется для компиляции регулярных выражений контекстов файлов в формат +.BR pcre (3). +.sp +Скомпилированный файл используется функциями проставления меток файлов libselinux. +.sp +По умолчанию +.B sefcontext_compile +записывает скомпилированный файл pcre с суффиксом +.B .bin +в конце (например, \fIinputfile\fB.bin\fR). +.SH ПАРАМЕТРЫ +.TP +.B \-o +Указать +.I outputfile +- должно быть полным именем файла, так как суффикс +.B .bin +не добавляется автоматически. +.TP +.B \-p +Указать двоичный +.I policyfile +для использования при проверке записей контекста в +.I inputfile +.br +Если найден недействительный контекст, запись файла в формате pcre не будет выполнена и появится сообщение об ошибке. + +.SH "ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ" +При ошибке возвращается -1. При успешном завершении возвращается 0. + +.SH "ПРИМЕРЫ" +.B Пример 1: +.br +sefcontext_compile /etc/selinux/targeted/contexts/files/file_contexts +.sp +В результате создаётся следующий файл: +.RS +/etc/selinux/targeted/contexts/files/file_contexts.bin +.RE +.sp +.B Пример 2: +.br +sefcontext_compile -o new_fc.bin /etc/selinux/targeted/contexts/files/file_contexts +.sp +В результате в текущем рабочем каталоге создаётся следующий файл: +.RS +new_fc.bin +.RE +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR semanage (8) +. +.SH АВТОРЫ +Dan Walsh, . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/selinux.8 b/man/ru/man8/selinux.8 new file mode 100644 index 0000000..5cc48df --- /dev/null +++ b/man/ru/man8/selinux.8 @@ -0,0 +1,106 @@ +.TH "selinux" "8" "29 апреля 2005" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +SELinux \- Linux с улучшенной безопасностью от NSA (SELinux) +. +.SH "ОПИСАНИЕ" +Linux с улучшенной безопасностью от NSA - это реализация гибкой архитектуры мандатного +управления доступом в операционной системе Linux. Архитектура SELinux предоставляет +общую поддержку использования различных видов политик мандатного управления доступом, +включая основанные на концепциях Type Enforcement® (принудительное присвоение типов), +Role-Based Access Control (управление доступом на основе ролей) и Multi-Level Security +(многоуровневая безопасность). Дополнительная информация и техническая документация по +SELinux доступна по адресу http://www.nsa.gov/research/selinux. + +Файл конфигурации +.I /etc/selinux/config +позволяет управлять включением и отключением SELinux и, если SELinux включён, +устанавливать режим его работы - разрешительный или принудительный. Переменной +.B SELINUX +можно задать значение отключённой, разрешительной или принудительной, чтобы выбрать +один из этих вариантов. Если выбрать отключение режима, код ядра и приложения SELinux +будет полностью отключён, система будет работать без какой-либо защиты SELinux. +При установке разрешительного режима код SELinux включён, но не выполняет отказы в +доступе, а только журналирует те действия, которые были бы запрещены при +принудительном режиме. При установке принудительного режима код SELinux включён, +выполняет отказы в доступе и журналирует соответствующие попытки доступа. Набор +отказов в доступе в разрешительном режиме может отличаться от этого набора в +принудительном режиме как по причине того, что принудительный режим предотвращает +дальнейшее выполнение операции после первого отказа, так и из-за того, что после +получения отказа в доступе часть кода приложения вернётся к работе в менее +привилегированном режиме. + +Файл конфигурации +.I /etc/selinux/config +также управляет тем, какая политика активна в системе. SELinux позволяет установить +в системе несколько политик, но одновременно можно использовать только одну из них. +В настоящее время имеется несколько видов политики SELinux, например, целевая политика +(targeted), политика многоуровневой безопасности (mls). Целевая политика позволяет +большинству процессов пользователя выполняться без ограничений, помещая в отдельные +домены безопасности, ограниченные политикой, только отдельные службы. Например, процессы +пользователя выполняются в никак не ограниченном домене, в то время как именованная +управляющая программа или управляющая программа apache будет выполняться в отдельном +специально настроенном домене. Если используется политика MLS (Multi-Level Security), +все процессы будут разделены по детально настроенным доменам безопасности и ограничены +политикой. MLS также поддерживает модель Белла — Лападулы, в которой процессы +ограничиваются не только по типу, но и по уровню данных. + +Чтобы определить, какая политика будет выполняться, следует установить переменную среды +.B SELINUXTYPE +в +.IR /etc/selinux/config . +Чтобы применить к системе изменение типа политики, необходимо перезагрузить систему и, +возможно, повторно проставить метки. В каталогах +.I /etc/selinux/{SELINUXTYPE}/ +необходимо установить для каждой такой политики соответствующую конфигурацию. + +Дальнейшую настройку отдельной политики SELinux можно выполнить с помощью набора настраиваемых +при компиляции параметров и набора логических переключателей среды выполнения политики. +.B \%system\-config\-selinux +позволяет настроить эти логические переключатели и настраиваемые параметры. + +Многие домены, которые защищены SELinux, также содержат man-страницы SELinux с информацией +о настройке соответствующей политики. +. +.SH "ПРОСТАВЛЕНИЕ МЕТОК ДЛЯ ФАЙЛОВ" +Всем файлам, каталогам, устройствам ... назначены контексты безопасности/метки. Эти контексты хранятся в расширенных атрибутах файловой системы. +Проблемы с SELinux часто возникают из-за неправильного проставления меток в файловой системе. Это может быть вызвано загрузкой компьютера с ядром, отличным от SELinux. Появление сообщения об ошибке, содержащего file_t, обычно означает серьёзную проблему с проставлением меток в файловой системе. + +Лучшим способом повторного проставления меток в файловой системе является создание файла флага +.I /.autorelabel +и последующая перезагрузка. +.BR system\-config\-selinux +также имеет эту функциональность. Кроме того, для повторного проставления меток для файлов можно использовать команды +.BR restorecon / fixfiles. +. +.SH ФАЙЛЫ +.I /etc/selinux/config +. +.SH "СМОТРИТЕ ТАКЖЕ" +.ad l +.nh +.BR booleans (8), +.BR setsebool (8), +.BR sepolicy (8), +.BR system-config-selinux (8), +.BR togglesebool (8), +.BR restorecon (8), +.BR fixfiles (8), +.BR setfiles (8), +.BR semanage (8), +.BR sepolicy (8) + +Для каждой ограниченной службы в системе имеется man-cтраница следующего формата: +.br + +.BR _selinux (8) + +Например, для службы httpd имеется страница +.BR httpd_selinux (8). + +.B man -k selinux + +Выведет список всех man-страниц SELinux. + +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/selinuxenabled.8 b/man/ru/man8/selinuxenabled.8 new file mode 100644 index 0000000..9c4af18 --- /dev/null +++ b/man/ru/man8/selinuxenabled.8 @@ -0,0 +1,21 @@ +.TH "selinuxenabled" "8" "7 апреля 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +selinuxenabled \- утилита для использования внутри сценариев оболочки, которая позволяет определить, включён ли selinux +. +.SH "ОБЗОР" +.B selinuxenabled +. +.SH "ОПИСАНИЕ" +Показывает, включён или отключён SELinux. +. +.SH "СОСТОЯНИЕ ВЫХОДА" +Выход с состоянием 0, если SELinux включён, и 1, если он отключён. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR setenforce (8), +.BR getenforce (8) +. +.SH АВТОРЫ +Dan Walsh, . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/selinuxexeccon.8 b/man/ru/man8/selinuxexeccon.8 new file mode 100644 index 0000000..3ddfe97 --- /dev/null +++ b/man/ru/man8/selinuxexeccon.8 @@ -0,0 +1,28 @@ +.TH "selinuxexeccon" "8" "14 мая 2011" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +selinuxexeccon \- сообщить контекст SELinux, который используется для этого исполняемого файла +. +.SH "ОБЗОР" +.B selinuxexeccon +.I command +.RI [ fromcon ] +. +.SH "ОПИСАНИЕ" +.B selinuxexeccon +сообщает контекст SELinux для указанной команды из указанного контекста или текущего контекста. +. +.SH ПРИМЕР +.nf +# selinuxexeccon /usr/bin/passwd +staff_u:staff_r:passwd_t:s0-s0:c0.c1023 + +# selinuxexeccon /usr/sbin/sendmail system_u:system_r:httpd_t:s0 +system_u:system_r:system_mail_t:s0 +.fi +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR secon (8) +. +.SH АВТОРЫ +Эта страница руководства была написана Dan Walsh . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/setenforce.8 b/man/ru/man8/setenforce.8 new file mode 100644 index 0000000..e0daad9 --- /dev/null +++ b/man/ru/man8/setenforce.8 @@ -0,0 +1,32 @@ +.TH "setenforce" "8" "7 апреля 2004" "dwalsh@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +setenforce \- изменить режим, в котором выполняется SELinux +. +.SH "ОБЗОР" +.B setenforce +.RB [ Enforcing | Permissive | 1 | 0 ] +. +.SH "ОПИСАНИЕ" +Используйте +.B Enforcing +или +.B 1 +для установки SELinux в принудительный режим. +.br +Используйте +.B Permissive +или +.B 0 +для установки SELinux в разрешительный режим. + +Если SELinux отключён и требуется его включить (или если SELinux включён и требуется его отключить), обратитесь к странице руководства +.BR selinux (8). +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR getenforce (8), +.BR selinuxenabled (8) +. +.SH АВТОРЫ +Dan Walsh, . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/man/ru/man8/togglesebool.8 b/man/ru/man8/togglesebool.8 new file mode 100644 index 0000000..1da9bcc --- /dev/null +++ b/man/ru/man8/togglesebool.8 @@ -0,0 +1,23 @@ +.TH "togglesebool" "8" "26 октября 2004" "sgrubb@redhat.com" "Документация по командной строке SELinux" +.SH "ИМЯ" +togglesebool \- переключить текущее значение логического переключателя SELinux +. +.SH "ОБЗОР" +.B togglesebool +.I boolean... +. +.SH "ОПИСАНИЕ" +.B togglesebool +переключает текущее значение списка логических переключателей. Если текущее значение 1, +то оно будет заменено на 0, и наоборот. Меняются только "находящиеся в памяти" значения; +параметры загрузки остаются без изменений. +. +.SH "СМОТРИТЕ ТАКЖЕ" +.BR selinux (8), +.BR booleans (8), +.BR getsebool (8), +.BR setsebool (8) +. +.SH АВТОРЫ +Эта страница руководства была написана Steve Grubb . +Перевод на русский язык выполнила Герасименко Олеся . diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..428afe5 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,4 @@ +selinux.py +selinuxswig_python_wrap.c +selinuxswig_python_exception.i +selinuxswig_ruby_wrap.c diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..f64f23a --- /dev/null +++ b/src/Makefile @@ -0,0 +1,200 @@ +# Support building the Python bindings multiple times, against various Python +# runtimes (e.g. Python 2 vs Python 3) by optionally prefixing the build +# targets with "PYPREFIX": +PYTHON ?= python3 +PYPREFIX ?= $(shell $(PYTHON) -c 'import sys;print("python-%d.%d" % sys.version_info[:2])') +RUBY ?= ruby +RUBYPREFIX ?= $(notdir $(RUBY)) +PKG_CONFIG ?= pkg-config + +# Installation directories. +PREFIX ?= /usr +LIBDIR ?= $(PREFIX)/lib +SHLIBDIR ?= /lib +INCLUDEDIR ?= $(PREFIX)/include +PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX)) +PYLIBS ?= $(shell $(PKG_CONFIG) --libs $(PYPREFIX)) +PYTHONLIBDIR ?= $(shell $(PYTHON) -c "from distutils.sysconfig import *; print(get_python_lib(plat_specific=1, prefix='$(PREFIX)'))") +PYCEXT ?= $(shell $(PYTHON) -c 'import imp;print([s for s,m,t in imp.get_suffixes() if t == imp.C_EXTENSION][0])') +RUBYINC ?= $(shell $(RUBY) -e 'puts "-I" + RbConfig::CONFIG["rubyarchhdrdir"] + " -I" + RbConfig::CONFIG["rubyhdrdir"]') +RUBYLIBS ?= $(shell $(RUBY) -e 'puts "-L" + RbConfig::CONFIG["libdir"] + " -L" + RbConfig::CONFIG["archlibdir"] + " " + RbConfig::CONFIG["LIBRUBYARG_SHARED"]') +RUBYINSTALL ?= $(shell $(RUBY) -e 'puts RbConfig::CONFIG["vendorarchdir"]') + +VERSION = $(shell cat ../VERSION) +LIBVERSION = 1 + +OS ?= $(shell uname) + +ifeq ($(shell $(CC) -v 2>&1 | grep "clang"),) +COMPILER ?= gcc +else +COMPILER ?= clang +endif + +LIBA=libselinux.a +TARGET=libselinux.so +LIBPC=libselinux.pc +SWIGIF= selinuxswig_python.i selinuxswig_python_exception.i +SWIGRUBYIF= selinuxswig_ruby.i +SWIGCOUT= selinuxswig_python_wrap.c +SWIGPYOUT= selinux.py +SWIGRUBYCOUT= selinuxswig_ruby_wrap.c +SWIGLOBJ:= $(patsubst %.c,$(PYPREFIX)%.lo,$(SWIGCOUT)) +SWIGRUBYLOBJ:= $(patsubst %.c,%.lo,$(SWIGRUBYCOUT)) +SWIGSO=$(PYPREFIX)_selinux.so +SWIGFILES=$(SWIGSO) $(SWIGPYOUT) +SWIGRUBYSO=$(RUBYPREFIX)_selinux.so +LIBSO=$(TARGET).$(LIBVERSION) +AUDIT2WHYLOBJ=$(PYPREFIX)audit2why.lo +AUDIT2WHYSO=$(PYPREFIX)audit2why.so + +# If no specific libsepol.a is specified, fall back on LDFLAGS search path +# Otherwise, as $(LIBSEPOLA) already appears in the dependencies, there +# is no need to define a value for LDLIBS_LIBSEPOLA +ifeq ($(LIBSEPOLA),) + LDLIBS_LIBSEPOLA := -l:libsepol.a +endif + +GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) $(SWIGCOUT) selinuxswig_python_exception.i +SRCS= $(filter-out $(GENERATED) audit2why.c, $(sort $(wildcard *.c))) + +MAX_STACK_SIZE=32768 + +ifeq ($(COMPILER), gcc) +EXTRA_CFLAGS = -fipa-pure-const -Wlogical-op -Wpacked-bitfield-compat -Wsync-nand \ + -Wcoverage-mismatch -Wcpp -Wformat-contains-nul -Wnormalized=nfc -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines -Wjump-misses-init \ + -Wno-suggest-attribute=pure -Wno-suggest-attribute=const -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 \ + -Wstrict-overflow=5 +else +EXTRA_CFLAGS = -Wunused-command-line-argument +endif + +OBJS= $(patsubst %.c,%.o,$(SRCS)) +LOBJS= $(patsubst %.c,%.lo,$(SRCS)) +CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissing-include-dirs \ + -Wunused -Wunknown-pragmas -Wstrict-aliasing -Wshadow -Wpointer-arith \ + -Wbad-function-cast -Wcast-align -Wwrite-strings -Waggregate-return \ + -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes \ + -Wmissing-declarations -Wmissing-noreturn -Wmissing-format-attribute \ + -Wredundant-decls -Wnested-externs -Winline -Winvalid-pch -Wvolatile-register-var \ + -Wdisabled-optimization -Wbuiltin-macro-redefined \ + -Wattributes -Wmultichar \ + -Wdeprecated-declarations -Wdiv-by-zero -Wdouble-promotion -Wendif-labels -Wextra \ + -Wformat-extra-args -Wformat-zero-length -Wformat=2 -Wmultichar \ + -Woverflow -Wpointer-to-int-cast -Wpragmas \ + -Wno-missing-field-initializers -Wno-sign-compare \ + -Wno-format-nonliteral -Wframe-larger-than=$(MAX_STACK_SIZE) \ + -fstack-protector-all --param=ssp-buffer-size=4 -fexceptions \ + -fasynchronous-unwind-tables -fdiagnostics-show-option -funit-at-a-time \ + -Werror -Wno-aggregate-return -Wno-redundant-decls \ + $(EXTRA_CFLAGS) + +LD_SONAME_FLAGS=-soname,$(LIBSO),-z,defs,-z,relro + +ifeq ($(OS), Darwin) +override CFLAGS += -I/opt/local/include +override LDFLAGS += -L/opt/local/lib -undefined dynamic_lookup +LD_SONAME_FLAGS=-install_name,$(LIBSO) +endif + +PCRE_LDLIBS ?= -lpcre +# override with -lfts when building on Musl libc to use fts-standalone +FTS_LDLIBS ?= + +override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS) + +RANLIB ?= ranlib + +ARCH := $(patsubst i%86,i386,$(shell uname -m)) +ifneq (,$(filter i386,$(ARCH))) +TLSFLAGS += -mno-tls-direct-seg-refs +endif + +ifeq ($(ANDROID_HOST),y) +DISABLE_FLAGS+= -DNO_MEDIA_BACKEND -DNO_DB_BACKEND -DNO_X_BACKEND \ + -DBUILD_HOST +SRCS= callbacks.c freecon.c label.c label_file.c \ + label_backends_android.c regex.c label_support.c \ + matchpathcon.c setrans_client.c sha1.c booleans.c +else +DISABLE_FLAGS+= -DNO_ANDROID_BACKEND +SRCS:= $(filter-out label_backends_android.c, $(SRCS)) +endif + +SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ $(DISABLE_FLAGS) + +all: $(LIBA) $(LIBSO) $(LIBPC) + +pywrap: all selinuxswig_python_exception.i + $(PYTHON) setup.py build_ext -I $(DESTDIR)$(INCLUDEDIR) -L $(DESTDIR)$(LIBDIR) + +rubywrap: all $(SWIGRUBYSO) + +$(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) + $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< + +$(SWIGRUBYSO): $(SWIGRUBYLOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -L. -shared -o $@ $^ -lselinux $(RUBYLIBS) + +$(LIBA): $(OBJS) + $(AR) rcs $@ $^ + $(RANLIB) $@ + +$(LIBSO): $(LOBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ $(PCRE_LDLIBS) $(FTS_LDLIBS) -ldl -Wl,$(LD_SONAME_FLAGS) + ln -sf $@ $(TARGET) + +$(LIBPC): $(LIBPC).in ../VERSION + sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBDIR):; s:@includedir@:$(INCLUDEDIR):; s:@PCRE_MODULE@:$(PCRE_MODULE):' < $< > $@ + +selinuxswig_python_exception.i: ../include/selinux/selinux.h + bash -e exception.sh > $@ || (rm -f $@ ; false) + +%.o: %.c policy.h + $(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $< + +%.lo: %.c policy.h + $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $< + +$(SWIGRUBYCOUT): $(SWIGRUBYIF) + $(SWIGRUBY) $< + +install: all + test -d $(DESTDIR)$(LIBDIR) || install -m 755 -d $(DESTDIR)$(LIBDIR) + install -m 644 $(LIBA) $(DESTDIR)$(LIBDIR) + test -d $(DESTDIR)$(SHLIBDIR) || install -m 755 -d $(DESTDIR)$(SHLIBDIR) + install -m 755 $(LIBSO) $(DESTDIR)$(SHLIBDIR) + test -d $(DESTDIR)$(LIBDIR)/pkgconfig || install -m 755 -d $(DESTDIR)$(LIBDIR)/pkgconfig + install -m 644 $(LIBPC) $(DESTDIR)$(LIBDIR)/pkgconfig + ln -sf --relative $(DESTDIR)$(SHLIBDIR)/$(LIBSO) $(DESTDIR)$(LIBDIR)/$(TARGET) + +install-pywrap: pywrap + $(PYTHON) setup.py install --prefix=$(PREFIX) `test -n "$(DESTDIR)" && echo --root $(DESTDIR)` + install -m 644 selinux.py $(DESTDIR)$(PYTHONLIBDIR)/selinux/__init__.py + +install-rubywrap: rubywrap + test -d $(DESTDIR)$(RUBYINSTALL) || install -m 755 -d $(DESTDIR)$(RUBYINSTALL) + install -m 755 $(SWIGRUBYSO) $(DESTDIR)$(RUBYINSTALL)/selinux.so + +relabel: + /sbin/restorecon $(DESTDIR)$(SHLIBDIR)/$(LIBSO) + +clean-pywrap: + -rm -f $(SWIGLOBJ) $(SWIGSO) $(AUDIT2WHYLOBJ) $(AUDIT2WHYSO) + $(PYTHON) setup.py clean + -rm -rf build *~ \#* *pyc .#* + +clean-rubywrap: + -rm -f $(SWIGRUBYLOBJ) $(SWIGRUBYSO) + +clean: clean-pywrap clean-rubywrap + -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) *.o *.lo *~ + +distclean: clean + rm -f $(GENERATED) $(SWIGFILES) + +indent: + ../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch])) + +.PHONY: all clean clean-pywrap clean-rubywrap pywrap rubywrap swigify install install-pywrap install-rubywrap distclean diff --git a/src/audit2why.c b/src/audit2why.c new file mode 100644 index 0000000..5a1e69a --- /dev/null +++ b/src/audit2why.c @@ -0,0 +1,493 @@ +/* Workaround for http://bugs.python.org/issue4835 */ +#ifndef SIZEOF_SOCKET_T +#define SIZEOF_SOCKET_T SIZEOF_INT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNKNOWN -1 +#define BADSCON -2 +#define BADTCON -3 +#define BADTCLASS -4 +#define BADPERM -5 +#define BADCOMPUTE -6 +#define NOPOLICY -7 +#define ALLOW 0 +#define DONTAUDIT 1 +#define TERULE 2 +#define BOOLEAN 3 +#define CONSTRAINT 4 +#define RBAC 5 +#define BOUNDS 6 + +struct boolean_t { + char *name; + int active; +}; + +static struct boolean_t **boollist = NULL; +static int boolcnt = 0; + +struct avc_t { + sepol_handle_t *handle; + sepol_policydb_t *policydb; + sepol_security_id_t ssid; + sepol_security_id_t tsid; + sepol_security_class_t tclass; + sepol_access_vector_t av; +}; + +static struct avc_t *avc = NULL; + +static sidtab_t sidtab; + +static int load_booleans(const sepol_bool_t * boolean, + void *arg __attribute__ ((__unused__))) +{ + boollist[boolcnt] = malloc(sizeof(struct boolean_t)); + boollist[boolcnt]->name = strdup(sepol_bool_get_name(boolean)); + boollist[boolcnt]->active = sepol_bool_get_value(boolean); + boolcnt++; + return 0; +} + +static int check_booleans(struct boolean_t **bools) +{ + char errormsg[PATH_MAX]; + struct sepol_av_decision avd; + unsigned int reason; + int rc; + int i; + sepol_bool_key_t *key = NULL; + sepol_bool_t *boolean = NULL; + int fcnt = 0; + int *foundlist = calloc(boolcnt, sizeof(int)); + if (!foundlist) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + return fcnt; + } + for (i = 0; i < boolcnt; i++) { + char *name = boollist[i]->name; + int active = boollist[i]->active; + rc = sepol_bool_key_create(avc->handle, name, &key); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, + "Could not create boolean key.\n"); + break; + } + rc = sepol_bool_query(avc->handle, + avc->policydb, + key, &boolean); + + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not find boolean %s.\n", name); + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + + sepol_bool_set_value(boolean, !active); + + rc = sepol_bool_set(avc->handle, + avc->policydb, + key, boolean); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not set boolean data %s.\n", name); + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + + /* Reproduce the computation. */ + rc = sepol_compute_av_reason(avc->ssid, avc->tsid, avc->tclass, + avc->av, &avd, &reason); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Error during access vector computation, skipping..."); + PyErr_SetString( PyExc_RuntimeError, errormsg); + + sepol_bool_free(boolean); + break; + } else { + if (!reason) { + foundlist[fcnt] = i; + fcnt++; + } + sepol_bool_set_value(boolean, active); + rc = sepol_bool_set(avc->handle, + avc->policydb, key, + boolean); + if (rc < 0) { + snprintf(errormsg, sizeof(errormsg), + "Could not set boolean data %s.\n", + name); + + PyErr_SetString( PyExc_RuntimeError, errormsg); + break; + } + } + sepol_bool_free(boolean); + sepol_bool_key_free(key); + key = NULL; + boolean = NULL; + } + if (key) + sepol_bool_key_free(key); + + if (boolean) + sepol_bool_free(boolean); + + if (fcnt > 0) { + *bools = calloc(sizeof(struct boolean_t), fcnt + 1); + struct boolean_t *b = *bools; + for (i = 0; i < fcnt; i++) { + int ctr = foundlist[i]; + b[i].name = strdup(boollist[ctr]->name); + b[i].active = !boollist[ctr]->active; + } + } + free(foundlist); + return fcnt; +} + +static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) { + PyObject *result = 0; + + if (PyArg_ParseTuple(args,(char *)":finish")) { + int i = 0; + if (! avc) + Py_RETURN_NONE; + + for (i = 0; i < boolcnt; i++) { + free(boollist[i]->name); + free(boollist[i]); + } + free(boollist); + sepol_sidtab_shutdown(&sidtab); + sepol_sidtab_destroy(&sidtab); + sepol_policydb_free(avc->policydb); + sepol_handle_destroy(avc->handle); + free(avc); + avc = NULL; + boollist = NULL; + boolcnt = 0; + + /* Boilerplate to return "None" */ + Py_RETURN_NONE; + } + return result; +} + + +static int __policy_init(const char *init_path) +{ + FILE *fp; + char path[PATH_MAX]; + char errormsg[PATH_MAX+1024+20]; + struct sepol_policy_file *pf = NULL; + int rc; + unsigned int cnt; + + path[PATH_MAX-1] = '\0'; + if (init_path) { + strncpy(path, init_path, PATH_MAX-1); + fp = fopen(path, "re"); + if (!fp) { + snprintf(errormsg, sizeof(errormsg), + "unable to open %s: %s\n", + path, strerror(errno)); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + } else { + const char *curpolicy = selinux_current_policy_path(); + if (!curpolicy) { + /* SELinux disabled, must use -p option. */ + snprintf(errormsg, sizeof(errormsg), + "You must specify the -p option with the path to the policy file.\n"); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + fp = fopen(curpolicy, "re"); + if (!fp) { + snprintf(errormsg, sizeof(errormsg), + "unable to open %s: %s\n", + curpolicy, + strerror(errno)); + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } + } + + avc = calloc(sizeof(struct avc_t), 1); + if (!avc) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + fclose(fp); + return 1; + } + + /* Set up a policydb directly so that we can mutate it later + for testing what booleans might have allowed the access. + Otherwise, we'd just use sepol_set_policydb_from_file() here. */ + if (sepol_policy_file_create(&pf) || + sepol_policydb_create(&avc->policydb)) { + snprintf(errormsg, sizeof(errormsg), + "policydb_init failed: %s\n", strerror(errno)); + PyErr_SetString( PyExc_RuntimeError, errormsg); + fclose(fp); + return 1; + } + sepol_policy_file_set_fp(pf, fp); + if (sepol_policydb_read(avc->policydb, pf)) { + snprintf(errormsg, sizeof(errormsg), + "invalid binary policy %s\n", path); + PyErr_SetString( PyExc_ValueError, errormsg); + fclose(fp); + return 1; + } + fclose(fp); + sepol_set_policydb(&avc->policydb->p); + avc->handle = sepol_handle_create(); + /* Turn off messages */ + sepol_msg_set_callback(avc->handle, NULL, NULL); + + rc = sepol_bool_count(avc->handle, + avc->policydb, &cnt); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); + return 1; + } + + boollist = calloc(cnt, sizeof(*boollist)); + if (!boollist) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); + return 1; + } + + sepol_bool_iterate(avc->handle, avc->policydb, + load_booleans, (void *)NULL); + + /* Initialize the sidtab for subsequent use by sepol_context_to_sid + and sepol_compute_av_reason. */ + rc = sepol_sidtab_init(&sidtab); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); + free(boollist); + return 1; + } + sepol_set_sidtab(&sidtab); + return 0; +} + +static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { + int result; + char *init_path=NULL; + if (avc) { + PyErr_SetString( PyExc_RuntimeError, "init called multiple times"); + return NULL; + } + if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) + return NULL; + result = __policy_init(init_path); + return Py_BuildValue("i", result); +} + +#define RETURN(X) \ + { \ + return Py_BuildValue("iO", (X), Py_None); \ + } + +static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { + char *reason_buf = NULL; + char * scon; + char * tcon; + char *tclassstr; + PyObject *listObj; + PyObject *strObj; + int numlines; + struct boolean_t *bools; + unsigned int reason; + sepol_security_id_t ssid, tsid; + sepol_security_class_t tclass; + sepol_access_vector_t perm, av; + struct sepol_av_decision avd; + int rc; + int i=0; + + if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) + return NULL; + + /* get the number of lines passed to us */ + numlines = PyList_Size(listObj); + + /* should raise an error here. */ + if (numlines < 0) return NULL; /* Not a list */ + + if (!avc) + RETURN(NOPOLICY) + + rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); + if (rc < 0) + RETURN(BADSCON) + + rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); + if (rc < 0) + RETURN(BADTCON) + + rc = sepol_string_to_security_class(tclassstr, &tclass); + if (rc < 0) + RETURN(BADTCLASS) + + /* Convert the permission list to an AV. */ + av = 0; + + /* iterate over items of the list, grabbing strings, and parsing + for numbers */ + for (i=0; i= 3 + permstr = _PyUnicode_AsString( strObj ); +#else + permstr = PyString_AsString( strObj ); +#endif + + rc = sepol_string_to_av_perm(tclass, permstr, &perm); + if (rc < 0) + RETURN(BADPERM) + + av |= perm; + } + + /* Reproduce the computation. */ + rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0); + if (rc < 0) + RETURN(BADCOMPUTE) + + if (!reason) + RETURN(ALLOW) + + if (reason & SEPOL_COMPUTEAV_TE) { + avc->ssid = ssid; + avc->tsid = tsid; + avc->tclass = tclass; + avc->av = av; + if (check_booleans(&bools) == 0) { + if (av & ~avd.auditdeny) { + RETURN(DONTAUDIT) + } else { + RETURN(TERULE) + } + } else { + PyObject *outboollist; + struct boolean_t *b = bools; + int len=0; + while (b->name) { + len++; b++; + } + b = bools; + outboollist = PyList_New(len); + len=0; + while(b->name) { + PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); + PyList_SetItem(outboollist, len++, bool_); + b++; + } + free(bools); + /* 'N' steals the reference to outboollist */ + return Py_BuildValue("iN", BOOLEAN, outboollist); + } + } + + if (reason & SEPOL_COMPUTEAV_CONS) { + if (reason_buf) { + PyObject *result = NULL; + result = Py_BuildValue("is", CONSTRAINT, reason_buf); + free(reason_buf); + return result; + } + RETURN(CONSTRAINT) + } + + if (reason & SEPOL_COMPUTEAV_RBAC) + RETURN(RBAC) + + if (reason & SEPOL_COMPUTEAV_BOUNDS) + RETURN(BOUNDS) + + RETURN(BADCOMPUTE) +} + +static PyMethodDef audit2whyMethods[] = { + {"init", init, METH_VARARGS, + "Initialize policy database."}, + {"analyze", analyze, METH_VARARGS, + "Analyze AVC."}, + {"finish", finish, METH_VARARGS, + "Finish using policy, free memory."}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 +/* Module-initialization logic specific to Python 3 */ +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "audit2why", + NULL, + 0, + audit2whyMethods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ +PyMODINIT_FUNC PyInit_audit2why(void) +#else +PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ +PyMODINIT_FUNC initaudit2why(void) +#endif +{ + PyObject *m; +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); + if (m == NULL) { + return NULL; + } +#else + m = Py_InitModule("audit2why", audit2whyMethods); +#endif + PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN); + PyModule_AddIntConstant(m,"BADSCON", BADSCON); + PyModule_AddIntConstant(m,"BADTCON", BADTCON); + PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS); + PyModule_AddIntConstant(m,"BADPERM", BADPERM); + PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE); + PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY); + PyModule_AddIntConstant(m,"ALLOW", ALLOW); + PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT); + PyModule_AddIntConstant(m,"TERULE", TERULE); + PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN); + PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT); + PyModule_AddIntConstant(m,"RBAC", RBAC); + PyModule_AddIntConstant(m,"BOUNDS", BOUNDS); + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} diff --git a/src/audit2why.map b/src/audit2why.map new file mode 100644 index 0000000..65989a8 --- /dev/null +++ b/src/audit2why.map @@ -0,0 +1,6 @@ +AUDIT2WHY_2.9 { + global: + initaudit2why; + PyInit_audit2why; + local: *; +}; diff --git a/src/avc.c b/src/avc.c new file mode 100644 index 0000000..5230efd --- /dev/null +++ b/src/avc.c @@ -0,0 +1,1180 @@ +/* + * Implementation of the userspace access vector cache (AVC). + * + * Author : Eamon Walsh + * + * Derived from the kernel AVC implementation by + * Stephen Smalley and + * James Morris . + */ +#include +#include "selinux_internal.h" +#include +#include "avc_sidtab.h" +#include "avc_internal.h" + +#define AVC_CACHE_SLOTS 512 +#define AVC_CACHE_MAXNODES 410 + +struct avc_entry { + security_id_t ssid; + security_id_t tsid; + security_class_t tclass; + struct av_decision avd; + security_id_t create_sid; + int used; /* used recently */ +}; + +struct avc_node { + struct avc_entry ae; + struct avc_node *next; +}; + +struct avc_cache { + struct avc_node *slots[AVC_CACHE_SLOTS]; + uint32_t lru_hint; /* LRU hint for reclaim scan */ + uint32_t active_nodes; + uint32_t latest_notif; /* latest revocation notification */ +}; + +struct avc_callback_node { + int (*callback) (uint32_t event, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, access_vector_t perms, + access_vector_t * out_retained); + uint32_t events; + security_id_t ssid; + security_id_t tsid; + security_class_t tclass; + access_vector_t perms; + struct avc_callback_node *next; +}; + +static void *avc_netlink_thread = NULL; +static void *avc_lock = NULL; +static void *avc_log_lock = NULL; +static struct avc_node *avc_node_freelist = NULL; +static struct avc_cache avc_cache; +static char *avc_audit_buf = NULL; +static struct avc_cache_stats cache_stats; +static struct avc_callback_node *avc_callbacks = NULL; +static struct sidtab avc_sidtab; + +static inline int avc_hash(security_id_t ssid, + security_id_t tsid, security_class_t tclass) +{ + return ((uintptr_t) ssid ^ ((uintptr_t) tsid << 2) ^ tclass) + & (AVC_CACHE_SLOTS - 1); +} + +int avc_context_to_sid_raw(const char * ctx, security_id_t * sid) +{ + int rc; + /* avc_init needs to be called before this function */ + assert(avc_running); + + avc_get_lock(avc_lock); + rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid); + avc_release_lock(avc_lock); + return rc; +} + +int avc_context_to_sid(const char * ctx, security_id_t * sid) +{ + int ret; + char * rctx; + + if (selinux_trans_to_raw_context(ctx, &rctx)) + return -1; + + ret = avc_context_to_sid_raw(rctx, sid); + + freecon(rctx); + + return ret; +} + +int avc_sid_to_context_raw(security_id_t sid, char ** ctx) +{ + int rc; + *ctx = NULL; + avc_get_lock(avc_lock); + *ctx = strdup(sid->ctx); /* caller must free via freecon */ + rc = *ctx ? 0 : -1; + avc_release_lock(avc_lock); + return rc; +} + +int avc_sid_to_context(security_id_t sid, char ** ctx) +{ + int ret; + char * rctx; + + ret = avc_sid_to_context_raw(sid, &rctx); + + if (ret == 0) { + ret = selinux_raw_to_trans_context(rctx, ctx); + freecon(rctx); + } + + return ret; +} + +int sidget(security_id_t sid __attribute__((unused))) +{ + return 1; +} + +int sidput(security_id_t sid __attribute__((unused))) +{ + return 1; +} + +int avc_get_initial_sid(const char * name, security_id_t * sid) +{ + int rc; + char * con; + + rc = security_get_initial_context_raw(name, &con); + if (rc < 0) + return rc; + rc = avc_context_to_sid_raw(con, sid); + + freecon(con); + + return rc; +} + +int avc_open(struct selinux_opt *opts, unsigned nopts) +{ + avc_setenforce = 0; + + while (nopts--) + switch(opts[nopts].type) { + case AVC_OPT_SETENFORCE: + avc_setenforce = 1; + avc_enforcing = !!opts[nopts].value; + break; + } + + return avc_init("avc", NULL, NULL, NULL, NULL); +} + +int avc_init(const char *prefix, + const struct avc_memory_callback *mem_cb, + const struct avc_log_callback *log_cb, + const struct avc_thread_callback *thread_cb, + const struct avc_lock_callback *lock_cb) +{ + struct avc_node *new; + int i, rc = 0; + + if (avc_running) + return 0; + + if (prefix) + strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1); + + set_callbacks(mem_cb, log_cb, thread_cb, lock_cb); + + avc_lock = avc_alloc_lock(); + avc_log_lock = avc_alloc_lock(); + + memset(&cache_stats, 0, sizeof(cache_stats)); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) + avc_cache.slots[i] = 0; + avc_cache.lru_hint = 0; + avc_cache.active_nodes = 0; + avc_cache.latest_notif = 0; + + rc = sidtab_init(&avc_sidtab); + if (rc) { + avc_log(SELINUX_ERROR, + "%s: unable to initialize SID table\n", + avc_prefix); + goto out; + } + + avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE); + if (!avc_audit_buf) { + avc_log(SELINUX_ERROR, + "%s: unable to allocate audit buffer\n", + avc_prefix); + rc = -1; + goto out; + } + + for (i = 0; i < AVC_CACHE_MAXNODES; i++) { + new = avc_malloc(sizeof(*new)); + if (!new) { + avc_log(SELINUX_WARNING, + "%s: warning: only got %d av entries\n", + avc_prefix, i); + break; + } + memset(new, 0, sizeof(*new)); + new->next = avc_node_freelist; + avc_node_freelist = new; + } + + if (!avc_setenforce) { + rc = security_getenforce(); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: could not determine enforcing mode: %s\n", + avc_prefix, + strerror(errno)); + goto out; + } + avc_enforcing = rc; + } + + rc = avc_netlink_open(0); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: can't open netlink socket: %d (%s)\n", + avc_prefix, errno, strerror(errno)); + goto out; + } + if (avc_using_threads) { + avc_netlink_thread = avc_create_thread(&avc_netlink_loop); + avc_netlink_trouble = 0; + } + avc_running = 1; + out: + return rc; +} + +void avc_cache_stats(struct avc_cache_stats *p) +{ + memcpy(p, &cache_stats, sizeof(cache_stats)); +} + +void avc_sid_stats(void) +{ + /* avc_init needs to be called before this function */ + assert(avc_running); + avc_get_lock(avc_log_lock); + avc_get_lock(avc_lock); + sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE); + avc_release_lock(avc_lock); + avc_log(SELINUX_INFO, "%s", avc_audit_buf); + avc_release_lock(avc_log_lock); +} + +void avc_av_stats(void) +{ + int i, chain_len, max_chain_len, slots_used; + struct avc_node *node; + + avc_get_lock(avc_lock); + + slots_used = 0; + max_chain_len = 0; + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + if (node) { + slots_used++; + chain_len = 0; + while (node) { + chain_len++; + node = node->next; + } + if (chain_len > max_chain_len) + max_chain_len = chain_len; + } + } + + avc_release_lock(avc_lock); + + avc_log(SELINUX_INFO, "%s: %u AV entries and %d/%d buckets used, " + "longest chain length %d\n", avc_prefix, + avc_cache.active_nodes, + slots_used, AVC_CACHE_SLOTS, max_chain_len); +} + +hidden_def(avc_av_stats) + +static inline struct avc_node *avc_reclaim_node(void) +{ + struct avc_node *prev, *cur; + int try; + uint32_t hvalue; + + hvalue = avc_cache.lru_hint; + for (try = 0; try < 2; try++) { + do { + prev = NULL; + cur = avc_cache.slots[hvalue]; + while (cur) { + if (!cur->ae.used) + goto found; + + cur->ae.used = 0; + + prev = cur; + cur = cur->next; + } + hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1); + } while (hvalue != avc_cache.lru_hint); + } + + errno = ENOMEM; /* this was a panic in the kernel... */ + return NULL; + + found: + avc_cache.lru_hint = hvalue; + + if (prev == NULL) + avc_cache.slots[hvalue] = cur->next; + else + prev->next = cur->next; + + return cur; +} + +static inline void avc_clear_avc_entry(struct avc_entry *ae) +{ + memset(ae, 0, sizeof(*ae)); +} + +static inline struct avc_node *avc_claim_node(security_id_t ssid, + security_id_t tsid, + security_class_t tclass) +{ + struct avc_node *new; + int hvalue; + + if (!avc_node_freelist) + avc_cleanup(); + + if (avc_node_freelist) { + new = avc_node_freelist; + avc_node_freelist = avc_node_freelist->next; + avc_cache.active_nodes++; + } else { + new = avc_reclaim_node(); + if (!new) + goto out; + } + + hvalue = avc_hash(ssid, tsid, tclass); + avc_clear_avc_entry(&new->ae); + new->ae.used = 1; + new->ae.ssid = ssid; + new->ae.tsid = tsid; + new->ae.tclass = tclass; + new->next = avc_cache.slots[hvalue]; + avc_cache.slots[hvalue] = new; + + out: + return new; +} + +static inline struct avc_node *avc_search_node(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + int *probes) +{ + struct avc_node *cur; + int hvalue; + int tprobes = 1; + + hvalue = avc_hash(ssid, tsid, tclass); + cur = avc_cache.slots[hvalue]; + while (cur != NULL && + (ssid != cur->ae.ssid || + tclass != cur->ae.tclass || tsid != cur->ae.tsid)) { + tprobes++; + cur = cur->next; + } + + if (cur == NULL) { + /* cache miss */ + goto out; + } + + /* cache hit */ + if (probes) + *probes = tprobes; + + cur->ae.used = 1; + + out: + return cur; +} + +/** + * avc_lookup - Look up an AVC entry. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * + * Look up an AVC entry that is valid for the + * @requested permissions between the SID pair + * (@ssid, @tsid), interpreting the permissions + * based on @tclass. If a valid AVC entry exists, + * then this function updates @aeref to refer to the + * entry and returns %0. Otherwise, -1 is returned. + */ +static int avc_lookup(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t requested, struct avc_entry_ref *aeref) +{ + struct avc_node *node; + int probes, rc = 0; + + avc_cache_stats_incr(cav_lookups); + node = avc_search_node(ssid, tsid, tclass, &probes); + + if (node && ((node->ae.avd.decided & requested) == requested)) { + avc_cache_stats_incr(cav_hits); + avc_cache_stats_add(cav_probes, probes); + aeref->ae = &node->ae; + goto out; + } + + avc_cache_stats_incr(cav_misses); + rc = -1; + out: + return rc; +} + +/** + * avc_insert - Insert an AVC entry. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @ae: AVC entry + * @aeref: AVC entry reference + * + * Insert an AVC entry for the SID pair + * (@ssid, @tsid) and class @tclass. + * The access vectors and the sequence number are + * normally provided by the security server in + * response to a security_compute_av() call. If the + * sequence number @ae->avd.seqno is not less than the latest + * revocation notification, then the function copies + * the access vectors into a cache entry, updates + * @aeref to refer to the entry, and returns %0. + * Otherwise, this function returns -%1 with @errno set to %EAGAIN. + */ +static int avc_insert(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + struct avc_entry *ae, struct avc_entry_ref *aeref) +{ + struct avc_node *node; + int rc = 0; + + if (ae->avd.seqno < avc_cache.latest_notif) { + avc_log(SELINUX_WARNING, + "%s: seqno %u < latest_notif %u\n", avc_prefix, + ae->avd.seqno, avc_cache.latest_notif); + errno = EAGAIN; + rc = -1; + goto out; + } + + node = avc_claim_node(ssid, tsid, tclass); + if (!node) { + rc = -1; + goto out; + } + + memcpy(&node->ae.avd, &ae->avd, sizeof(ae->avd)); + aeref->ae = &node->ae; + out: + return rc; +} + +void avc_cleanup(void) +{ +} + +hidden_def(avc_cleanup) + +int avc_reset(void) +{ + struct avc_callback_node *c; + int i, ret, rc = 0, errsave = 0; + struct avc_node *node, *tmp; + errno = 0; + + if (!avc_running) + return 0; + + avc_get_lock(avc_lock); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + while (node) { + tmp = node; + node = node->next; + avc_clear_avc_entry(&tmp->ae); + tmp->next = avc_node_freelist; + avc_node_freelist = tmp; + avc_cache.active_nodes--; + } + avc_cache.slots[i] = 0; + } + avc_cache.lru_hint = 0; + + avc_release_lock(avc_lock); + + memset(&cache_stats, 0, sizeof(cache_stats)); + + for (c = avc_callbacks; c; c = c->next) { + if (c->events & AVC_CALLBACK_RESET) { + ret = c->callback(AVC_CALLBACK_RESET, 0, 0, 0, 0, 0); + if (ret && !rc) { + rc = ret; + errsave = errno; + } + } + } + errno = errsave; + return rc; +} + +hidden_def(avc_reset) + +void avc_destroy(void) +{ + struct avc_callback_node *c; + struct avc_node *node, *tmp; + int i; + /* avc_init needs to be called before this function */ + assert(avc_running); + + avc_get_lock(avc_lock); + + if (avc_using_threads) + avc_stop_thread(avc_netlink_thread); + avc_netlink_close(); + + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + node = avc_cache.slots[i]; + while (node) { + tmp = node; + node = node->next; + avc_free(tmp); + } + } + while (avc_node_freelist) { + tmp = avc_node_freelist; + avc_node_freelist = tmp->next; + avc_free(tmp); + } + avc_release_lock(avc_lock); + + while (avc_callbacks) { + c = avc_callbacks; + avc_callbacks = c->next; + avc_free(c); + } + sidtab_destroy(&avc_sidtab); + avc_free_lock(avc_lock); + avc_free_lock(avc_log_lock); + avc_free(avc_audit_buf); + avc_running = 0; +} + +/* ratelimit stuff put aside for now --EFW */ +#if 0 +/* + * Copied from net/core/utils.c:net_ratelimit and modified for + * use by the AVC audit facility. + */ +#define AVC_MSG_COST 5*HZ +#define AVC_MSG_BURST 10*5*HZ + +/* + * This enforces a rate limit: not more than one kernel message + * every 5secs to make a denial-of-service attack impossible. + */ +static int avc_ratelimit(void) +{ + static unsigned long toks = 10 * 5 * HZ; + static unsigned long last_msg; + static int missed, rc = 0; + unsigned long now = jiffies; + void *ratelimit_lock = avc_alloc_lock(); + + avc_get_lock(ratelimit_lock); + toks += now - last_msg; + last_msg = now; + if (toks > AVC_MSG_BURST) + toks = AVC_MSG_BURST; + if (toks >= AVC_MSG_COST) { + int lost = missed; + missed = 0; + toks -= AVC_MSG_COST; + avc_release_lock(ratelimit_lock); + if (lost) { + avc_log(SELINUX_WARNING, + "%s: %d messages suppressed.\n", avc_prefix, + lost); + } + rc = 1; + goto out; + } + missed++; + avc_release_lock(ratelimit_lock); + out: + avc_free_lock(ratelimit_lock); + return rc; +} + +static inline int check_avc_ratelimit(void) +{ + if (avc_enforcing) + return avc_ratelimit(); + else { + /* If permissive, then never suppress messages. */ + return 1; + } +} +#endif /* ratelimit stuff */ + +/** + * avc_dump_av - Display an access vector in human-readable form. + * @tclass: target security class + * @av: access vector + */ +static void avc_dump_av(security_class_t tclass, access_vector_t av) +{ + const char *permstr; + access_vector_t bit = 1; + + if (av == 0) { + log_append(avc_audit_buf, " null"); + return; + } + + log_append(avc_audit_buf, " {"); + + while (av) { + if (av & bit) { + permstr = security_av_perm_to_string(tclass, bit); + if (!permstr) + break; + log_append(avc_audit_buf, " %s", permstr); + av &= ~bit; + } + bit <<= 1; + } + + if (av) + log_append(avc_audit_buf, " 0x%x", av); + log_append(avc_audit_buf, " }"); +} + +/** + * avc_dump_query - Display a SID pair and a class in human-readable form. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + */ +static void avc_dump_query(security_id_t ssid, security_id_t tsid, + security_class_t tclass) +{ + avc_get_lock(avc_lock); + + log_append(avc_audit_buf, "scontext=%s tcontext=%s", + ssid->ctx, tsid->ctx); + + avc_release_lock(avc_lock); + log_append(avc_audit_buf, " tclass=%s", + security_class_to_string(tclass)); +} + +void avc_audit(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct av_decision *avd, int result, void *a) +{ + access_vector_t denied, audited; + + denied = requested & ~avd->allowed; + if (denied) + audited = denied & avd->auditdeny; + else if (!requested || result) + audited = denied = requested; + else + audited = requested & avd->auditallow; + if (!audited) + return; +#if 0 + if (!check_avc_ratelimit()) + return; +#endif + /* prevent overlapping buffer writes */ + avc_get_lock(avc_log_lock); + snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE, + "%s: %s ", avc_prefix, (denied || !requested) ? "denied" : "granted"); + avc_dump_av(tclass, audited); + log_append(avc_audit_buf, " for "); + + /* get any extra information printed by the callback */ + avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf), + AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf)); + + log_append(avc_audit_buf, " "); + avc_dump_query(ssid, tsid, tclass); + + if (denied) + log_append(avc_audit_buf, " permissive=%u", result ? 0 : 1); + + log_append(avc_audit_buf, "\n"); + avc_log(SELINUX_AVC, "%s", avc_audit_buf); + + avc_release_lock(avc_log_lock); +} + +hidden_def(avc_audit) + + +static void avd_init(struct av_decision *avd) +{ + avd->allowed = 0; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = avc_cache.latest_notif; + avd->flags = 0; +} + +int avc_has_perm_noaudit(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, struct av_decision *avd) +{ + struct avc_entry *ae; + int rc = 0; + struct avc_entry entry; + access_vector_t denied; + struct avc_entry_ref ref; + + if (avd) + avd_init(avd); + + if (!avc_using_threads && !avc_app_main_loop) { + (void)avc_netlink_check_nb(); + } + + if (!aeref) { + avc_entry_ref_init(&ref); + aeref = &ref; + } + + avc_get_lock(avc_lock); + avc_cache_stats_incr(entry_lookups); + ae = aeref->ae; + if (ae) { + if (ae->ssid == ssid && + ae->tsid == tsid && + ae->tclass == tclass && + ((ae->avd.decided & requested) == requested)) { + avc_cache_stats_incr(entry_hits); + ae->used = 1; + } else { + avc_cache_stats_incr(entry_discards); + ae = 0; + } + } + + if (!ae) { + avc_cache_stats_incr(entry_misses); + rc = avc_lookup(ssid, tsid, tclass, requested, aeref); + if (rc) { + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, requested, + &entry.avd); + if (rc && errno == EINVAL && !avc_enforcing) { + rc = errno = 0; + goto out; + } + if (rc) + goto out; + rc = avc_insert(ssid, tsid, tclass, &entry, aeref); + if (rc) + goto out; + } + ae = aeref->ae; + } + + if (avd) + memcpy(avd, &ae->avd, sizeof(*avd)); + + denied = requested & ~(ae->avd.allowed); + + if (!requested || denied) { + if (!avc_enforcing || + (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)) + ae->avd.allowed |= requested; + else { + errno = EACCES; + rc = -1; + } + } + + out: + avc_release_lock(avc_lock); + return rc; +} + +hidden_def(avc_has_perm_noaudit) + +int avc_has_perm(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata) +{ + struct av_decision avd; + int errsave, rc; + + rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd); + errsave = errno; + avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); + errno = errsave; + return rc; +} + +int avc_compute_create(security_id_t ssid, security_id_t tsid, + security_class_t tclass, security_id_t *newsid) +{ + int rc; + struct avc_entry_ref aeref; + struct avc_entry entry; + char * ctx; + + *newsid = NULL; + avc_entry_ref_init(&aeref); + + avc_get_lock(avc_lock); + + /* check for a cached entry */ + rc = avc_lookup(ssid, tsid, tclass, 0, &aeref); + if (rc) { + /* need to make a cache entry for this tuple */ + rc = security_compute_av_flags_raw(ssid->ctx, tsid->ctx, + tclass, 0, &entry.avd); + if (rc) + goto out; + rc = avc_insert(ssid, tsid, tclass, &entry, &aeref); + if (rc) + goto out; + } + + /* check for a saved compute_create value */ + if (!aeref.ae->create_sid) { + /* need to query the kernel policy */ + rc = security_compute_create_raw(ssid->ctx, tsid->ctx, tclass, + &ctx); + if (rc) + goto out; + rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid); + freecon(ctx); + if (rc) + goto out; + + aeref.ae->create_sid = *newsid; + } else { + /* found saved value */ + *newsid = aeref.ae->create_sid; + } + + rc = 0; +out: + avc_release_lock(avc_lock); + return rc; +} + +int avc_compute_member(security_id_t ssid, security_id_t tsid, + security_class_t tclass, security_id_t *newsid) +{ + int rc; + char * ctx = NULL; + *newsid = NULL; + /* avc_init needs to be called before this function */ + assert(avc_running); + avc_get_lock(avc_lock); + + rc = security_compute_member_raw(ssid->ctx, tsid->ctx, tclass, &ctx); + if (rc) + goto out; + rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid); + freecon(ctx); +out: + avc_release_lock(avc_lock); + return rc; +} + +int avc_add_callback(int (*callback) (uint32_t event, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t perms, + access_vector_t * out_retained), + uint32_t events, security_id_t ssid, + security_id_t tsid, + security_class_t tclass, access_vector_t perms) +{ + struct avc_callback_node *c; + int rc = 0; + + c = avc_malloc(sizeof(*c)); + if (!c) { + rc = -1; + goto out; + } + + c->callback = callback; + c->events = events; + c->ssid = ssid; + c->tsid = tsid; + c->tclass = tclass; + c->perms = perms; + c->next = avc_callbacks; + avc_callbacks = c; + out: + return rc; +} + +static inline int avc_sidcmp(security_id_t x, security_id_t y) +{ + return (x == y || x == SECSID_WILD || y == SECSID_WILD); +} + +static inline void avc_update_node(uint32_t event, struct avc_node *node, + access_vector_t perms) +{ + switch (event) { + case AVC_CALLBACK_GRANT: + node->ae.avd.allowed |= perms; + break; + case AVC_CALLBACK_TRY_REVOKE: + case AVC_CALLBACK_REVOKE: + node->ae.avd.allowed &= ~perms; + break; + case AVC_CALLBACK_AUDITALLOW_ENABLE: + node->ae.avd.auditallow |= perms; + break; + case AVC_CALLBACK_AUDITALLOW_DISABLE: + node->ae.avd.auditallow &= ~perms; + break; + case AVC_CALLBACK_AUDITDENY_ENABLE: + node->ae.avd.auditdeny |= perms; + break; + case AVC_CALLBACK_AUDITDENY_DISABLE: + node->ae.avd.auditdeny &= ~perms; + break; + } +} + +static int avc_update_cache(uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms) +{ + struct avc_node *node; + int i; + + avc_get_lock(avc_lock); + + if (ssid == SECSID_WILD || tsid == SECSID_WILD) { + /* apply to all matching nodes */ + for (i = 0; i < AVC_CACHE_SLOTS; i++) { + for (node = avc_cache.slots[i]; node; node = node->next) { + if (avc_sidcmp(ssid, node->ae.ssid) && + avc_sidcmp(tsid, node->ae.tsid) && + tclass == node->ae.tclass) { + avc_update_node(event, node, perms); + } + } + } + } else { + /* apply to one node */ + node = avc_search_node(ssid, tsid, tclass, 0); + if (node) { + avc_update_node(event, node, perms); + } + } + + avc_release_lock(avc_lock); + + return 0; +} + +/* avc_control - update cache and call callbacks + * + * This should not be called directly; use the individual event + * functions instead. + */ +static int avc_control(uint32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms, + uint32_t seqno, access_vector_t * out_retained) +{ + struct avc_callback_node *c; + access_vector_t tretained = 0, cretained = 0; + int ret, rc = 0, errsave = 0; + errno = 0; + + /* + * try_revoke only removes permissions from the cache + * state if they are not retained by the object manager. + * Hence, try_revoke must wait until after the callbacks have + * been invoked to update the cache state. + */ + if (event != AVC_CALLBACK_TRY_REVOKE) + avc_update_cache(event, ssid, tsid, tclass, perms); + + for (c = avc_callbacks; c; c = c->next) { + if ((c->events & event) && + avc_sidcmp(c->ssid, ssid) && + avc_sidcmp(c->tsid, tsid) && + c->tclass == tclass && (c->perms & perms)) { + cretained = 0; + ret = c->callback(event, ssid, tsid, tclass, + (c->perms & perms), &cretained); + if (ret && !rc) { + rc = ret; + errsave = errno; + } + if (!ret) + tretained |= cretained; + } + } + + if (event == AVC_CALLBACK_TRY_REVOKE) { + /* revoke any unretained permissions */ + perms &= ~tretained; + avc_update_cache(event, ssid, tsid, tclass, perms); + *out_retained = tretained; + } + + avc_get_lock(avc_lock); + if (seqno > avc_cache.latest_notif) + avc_cache.latest_notif = seqno; + avc_release_lock(avc_lock); + + errno = errsave; + return rc; +} + +/** + * avc_ss_grant - Grant previously denied permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + */ +int avc_ss_grant(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) +{ + return avc_control(AVC_CALLBACK_GRANT, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_try_revoke - Try to revoke previously granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @out_retained: subset of @perms that are retained + * + * Try to revoke previously granted permissions, but + * only if they are not retained as migrated permissions. + * Return the subset of permissions that are retained via @out_retained. + */ +int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t perms, uint32_t seqno, + access_vector_t * out_retained) +{ + return avc_control(AVC_CALLBACK_TRY_REVOKE, + ssid, tsid, tclass, perms, seqno, out_retained); +} + +/** + * avc_ss_revoke - Revoke previously granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * + * Revoke previously granted permissions, even if + * they are retained as migrated permissions. + */ +int avc_ss_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) +{ + return avc_control(AVC_CALLBACK_REVOKE, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_reset - Flush the cache and revalidate migrated permissions. + * @seqno: policy sequence number + */ +int avc_ss_reset(uint32_t seqno) +{ + int rc; + + rc = avc_reset(); + + avc_get_lock(avc_lock); + if (seqno > avc_cache.latest_notif) + avc_cache.latest_notif = seqno; + avc_release_lock(avc_lock); + + return rc; +} + +/** + * avc_ss_set_auditallow - Enable or disable auditing of granted permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @enable: enable flag. + */ +int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) +{ + if (enable) + return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE, + ssid, tsid, tclass, perms, seqno, 0); + else + return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE, + ssid, tsid, tclass, perms, seqno, 0); +} + +/** + * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions. + * @ssid: source security identifier or %SECSID_WILD + * @tsid: target security identifier or %SECSID_WILD + * @tclass: target security class + * @perms: permissions to grant + * @seqno: policy sequence number + * @enable: enable flag. + */ +int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) +{ + if (enable) + return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE, + ssid, tsid, tclass, perms, seqno, 0); + else + return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE, + ssid, tsid, tclass, perms, seqno, 0); +} diff --git a/src/avc_internal.c b/src/avc_internal.c new file mode 100644 index 0000000..49cecc9 --- /dev/null +++ b/src/avc_internal.c @@ -0,0 +1,293 @@ +/* + * Callbacks for user-supplied memory allocation, supplemental + * auditing, and locking routines. + * + * Author : Eamon Walsh + * + * Netlink code derived in part from sample code by + * James Morris . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "selinux_netlink.h" +#include "avc_internal.h" + +#ifndef NETLINK_SELINUX +#define NETLINK_SELINUX 7 +#endif + +/* callback pointers */ +void *(*avc_func_malloc) (size_t) = NULL; +void (*avc_func_free) (void *) = NULL; + +void (*avc_func_log) (const char *, ...) = NULL; +void (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL; + +int avc_using_threads = 0; +int avc_app_main_loop = 0; +void *(*avc_func_create_thread) (void (*)(void)) = NULL; +void (*avc_func_stop_thread) (void *) = NULL; + +void *(*avc_func_alloc_lock) (void) = NULL; +void (*avc_func_get_lock) (void *) = NULL; +void (*avc_func_release_lock) (void *) = NULL; +void (*avc_func_free_lock) (void *) = NULL; + +/* message prefix string and avc enforcing mode */ +char avc_prefix[AVC_PREFIX_SIZE] = "uavc"; +int avc_running = 0; +int avc_enforcing = 1; +int avc_setenforce = 0; +int avc_netlink_trouble = 0; + +/* netlink socket code */ +static int fd = -1; + +int avc_netlink_open(int blocking) +{ + int len, rc = 0; + struct sockaddr_nl addr; + + fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_SELINUX); + if (fd < 0) { + rc = fd; + goto out; + } + + if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) { + close(fd); + fd = -1; + rc = -1; + goto out; + } + + len = sizeof(addr); + + memset(&addr, 0, len); + addr.nl_family = AF_NETLINK; + addr.nl_groups = SELNL_GRP_AVC; + + if (bind(fd, (struct sockaddr *)&addr, len) < 0) { + close(fd); + fd = -1; + rc = -1; + goto out; + } + out: + return rc; +} + +void avc_netlink_close(void) +{ + if (fd >= 0) + close(fd); + fd = -1; +} + +static int avc_netlink_receive(void *buf, unsigned buflen, int blocking) +{ + int rc; + struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 }; + struct sockaddr_nl nladdr; + socklen_t nladdrlen = sizeof nladdr; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + do { + rc = poll(&pfd, 1, (blocking ? -1 : 0)); + } while (rc < 0 && errno == EINTR); + + if (rc == 0 && !blocking) { + errno = EWOULDBLOCK; + return -1; + } + else if (rc < 1) { + avc_log(SELINUX_ERROR, "%s: netlink poll: error %d\n", + avc_prefix, errno); + return rc; + } + + rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr, + &nladdrlen); + if (rc < 0) + return rc; + + if (nladdrlen != sizeof nladdr) { + avc_log(SELINUX_WARNING, + "%s: warning: netlink address truncated, len %u?\n", + avc_prefix, nladdrlen); + return -1; + } + + if (nladdr.nl_pid) { + avc_log(SELINUX_WARNING, + "%s: warning: received spoofed netlink packet from: %u\n", + avc_prefix, nladdr.nl_pid); + return -1; + } + + if (rc == 0) { + avc_log(SELINUX_WARNING, + "%s: warning: received EOF on netlink socket\n", + avc_prefix); + errno = EBADFD; + return -1; + } + + if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) { + avc_log(SELINUX_WARNING, + "%s: warning: incomplete netlink message\n", + avc_prefix); + return -1; + } + + return 0; +} + +static int avc_netlink_process(void *buf) +{ + int rc; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + switch (nlh->nlmsg_type) { + case NLMSG_ERROR:{ + struct nlmsgerr *err = NLMSG_DATA(nlh); + + /* Netlink ack */ + if (err->error == 0) + break; + + errno = -err->error; + avc_log(SELINUX_ERROR, + "%s: netlink error: %d\n", avc_prefix, errno); + return -1; + } + + case SELNL_MSG_SETENFORCE:{ + struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh); + msg->val = !!msg->val; + avc_log(SELINUX_INFO, + "%s: received setenforce notice (enforcing=%d)\n", + avc_prefix, msg->val); + if (avc_setenforce) + break; + avc_enforcing = msg->val; + if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) { + avc_log(SELINUX_ERROR, + "%s: cache reset returned %d (errno %d)\n", + avc_prefix, rc, errno); + return rc; + } + rc = selinux_netlink_setenforce(msg->val); + if (rc < 0) + return rc; + break; + } + + case SELNL_MSG_POLICYLOAD:{ + struct selnl_msg_policyload *msg = NLMSG_DATA(nlh); + avc_log(SELINUX_INFO, + "%s: received policyload notice (seqno=%u)\n", + avc_prefix, msg->seqno); + rc = avc_ss_reset(msg->seqno); + if (rc < 0) { + avc_log(SELINUX_ERROR, + "%s: cache reset returned %d (errno %d)\n", + avc_prefix, rc, errno); + return rc; + } + rc = selinux_netlink_policyload(msg->seqno); + if (rc < 0) + return rc; + break; + } + + default: + avc_log(SELINUX_WARNING, + "%s: warning: unknown netlink message %d\n", + avc_prefix, nlh->nlmsg_type); + } + return 0; +} + +int avc_netlink_check_nb(void) +{ + int rc; + char buf[1024] __attribute__ ((aligned)); + + while (1) { + errno = 0; + rc = avc_netlink_receive(buf, sizeof(buf), 0); + if (rc < 0) { + if (errno == EWOULDBLOCK) + return 0; + if (errno == 0 || errno == EINTR) + continue; + else { + avc_log(SELINUX_ERROR, + "%s: netlink recvfrom: error %d\n", + avc_prefix, errno); + return rc; + } + } + + (void)avc_netlink_process(buf); + } + return 0; +} + +/* run routine for the netlink listening thread */ +void avc_netlink_loop(void) +{ + int rc; + char buf[1024] __attribute__ ((aligned)); + + while (1) { + errno = 0; + rc = avc_netlink_receive(buf, sizeof(buf), 1); + if (rc < 0) { + if (errno == 0 || errno == EINTR) + continue; + else { + avc_log(SELINUX_ERROR, + "%s: netlink recvfrom: error %d\n", + avc_prefix, errno); + break; + } + } + + rc = avc_netlink_process(buf); + if (rc < 0) + break; + } + + close(fd); + fd = -1; + avc_netlink_trouble = 1; + avc_log(SELINUX_ERROR, + "%s: netlink thread: errors encountered, terminating\n", + avc_prefix); +} + +int avc_netlink_acquire_fd(void) +{ + avc_app_main_loop = 1; + + return fd; +} + +void avc_netlink_release_fd(void) +{ + avc_app_main_loop = 0; +} diff --git a/src/avc_internal.h b/src/avc_internal.h new file mode 100644 index 0000000..f851659 --- /dev/null +++ b/src/avc_internal.h @@ -0,0 +1,182 @@ +/* + * This file describes the internal interface used by the AVC + * for calling the user-supplied memory allocation, supplemental + * auditing, and locking routine, as well as incrementing the + * statistics fields. + * + * Author : Eamon Walsh + */ +#ifndef _SELINUX_AVC_INTERNAL_H_ +#define _SELINUX_AVC_INTERNAL_H_ + +#include +#include +#include +#include +#include "callbacks.h" +#include "dso.h" + +/* callback pointers */ +extern void *(*avc_func_malloc) (size_t) hidden; +extern void (*avc_func_free) (void *)hidden; + +extern void (*avc_func_log) (const char *, ...) __attribute__((__format__(printf,1,2))) hidden; +extern void (*avc_func_audit) (void *, security_class_t, char *, size_t)hidden; + +extern int avc_using_threads hidden; +extern int avc_app_main_loop hidden; +extern void *(*avc_func_create_thread) (void (*)(void))hidden; +extern void (*avc_func_stop_thread) (void *)hidden; + +extern void *(*avc_func_alloc_lock) (void)hidden; +extern void (*avc_func_get_lock) (void *)hidden; +extern void (*avc_func_release_lock) (void *)hidden; +extern void (*avc_func_free_lock) (void *)hidden; + +static inline void set_callbacks(const struct avc_memory_callback *mem_cb, + const struct avc_log_callback *log_cb, + const struct avc_thread_callback *thread_cb, + const struct avc_lock_callback *lock_cb) +{ + if (mem_cb) { + avc_func_malloc = mem_cb->func_malloc; + avc_func_free = mem_cb->func_free; + } + if (log_cb) { + avc_func_log = log_cb->func_log; + avc_func_audit = log_cb->func_audit; + } + if (thread_cb) { + avc_using_threads = 1; + avc_func_create_thread = thread_cb->func_create_thread; + avc_func_stop_thread = thread_cb->func_stop_thread; + } + if (lock_cb) { + avc_func_alloc_lock = lock_cb->func_alloc_lock; + avc_func_get_lock = lock_cb->func_get_lock; + avc_func_release_lock = lock_cb->func_release_lock; + avc_func_free_lock = lock_cb->func_free_lock; + } +} + +/* message prefix and enforcing mode*/ +#define AVC_PREFIX_SIZE 16 +extern char avc_prefix[AVC_PREFIX_SIZE] hidden; +extern int avc_running hidden; +extern int avc_enforcing hidden; +extern int avc_setenforce hidden; + +/* user-supplied callback interface for avc */ +static inline void *avc_malloc(size_t size) +{ + return avc_func_malloc ? avc_func_malloc(size) : malloc(size); +} + +static inline void avc_free(void *ptr) +{ + if (avc_func_free) + avc_func_free(ptr); + else + free(ptr); +} + +/* this is a macro in order to use the variadic capability. */ +#define avc_log(type, format...) \ + if (avc_func_log) \ + avc_func_log(format); \ + else \ + selinux_log(type, format); + +static inline void avc_suppl_audit(void *ptr, security_class_t class, + char *buf, size_t len) +{ + if (avc_func_audit) + avc_func_audit(ptr, class, buf, len); + else + selinux_audit(ptr, class, buf, len); +} + +static inline void *avc_create_thread(void (*run) (void)) +{ + return avc_func_create_thread ? avc_func_create_thread(run) : NULL; +} + +static inline void avc_stop_thread(void *thread) +{ + if (avc_func_stop_thread) + avc_func_stop_thread(thread); +} + +static inline void *avc_alloc_lock(void) +{ + return avc_func_alloc_lock ? avc_func_alloc_lock() : NULL; +} + +static inline void avc_get_lock(void *lock) +{ + if (avc_func_get_lock) + avc_func_get_lock(lock); +} + +static inline void avc_release_lock(void *lock) +{ + if (avc_func_release_lock) + avc_func_release_lock(lock); +} + +static inline void avc_free_lock(void *lock) +{ + if (avc_func_free_lock) + avc_func_free_lock(lock); +} + +/* statistics helper routines */ +#ifdef AVC_CACHE_STATS + +#define avc_cache_stats_incr(field) \ + cache_stats.field ++; +#define avc_cache_stats_add(field, num) \ + cache_stats.field += num; + +#else + +#define avc_cache_stats_incr(field) +#define avc_cache_stats_add(field, num) + +#endif + +/* logging helper routines */ +#define AVC_AUDIT_BUFSIZE 1024 + +/* again, we need the variadic capability here */ +#define log_append(buf,format...) \ + snprintf(buf+strlen(buf), AVC_AUDIT_BUFSIZE-strlen(buf), format) + +/* internal callbacks */ +int avc_ss_grant(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) hidden; +int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, + access_vector_t perms, uint32_t seqno, + access_vector_t * out_retained) hidden; +int avc_ss_revoke(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno) hidden; +int avc_ss_reset(uint32_t seqno) hidden; +int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) hidden; +int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms, + uint32_t seqno, uint32_t enable) hidden; + +/* netlink kernel message code */ +extern int avc_netlink_trouble hidden; + +hidden_proto(avc_av_stats) + hidden_proto(avc_cleanup) + hidden_proto(avc_reset) + hidden_proto(avc_audit) + hidden_proto(avc_has_perm_noaudit) +#endif /* _SELINUX_AVC_INTERNAL_H_ */ diff --git a/src/avc_sidtab.c b/src/avc_sidtab.c new file mode 100644 index 0000000..c775430 --- /dev/null +++ b/src/avc_sidtab.c @@ -0,0 +1,157 @@ +/* + * Implementation of the userspace SID hashtable. + * + * Author : Eamon Walsh, + */ +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include +#include "avc_sidtab.h" +#include "avc_internal.h" + +static inline unsigned sidtab_hash(const char * key) +{ + char *p, *keyp; + unsigned int size; + unsigned int val; + + val = 0; + keyp = (char *)key; + size = strlen(keyp); + for (p = keyp; (unsigned int)(p - keyp) < size; p++) + val = + (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); + return val & (SIDTAB_SIZE - 1); +} + +int sidtab_init(struct sidtab *s) +{ + int i, rc = 0; + + s->htable = (struct sidtab_node **)avc_malloc + (sizeof(struct sidtab_node *) * SIDTAB_SIZE); + + if (!s->htable) { + rc = -1; + goto out; + } + for (i = 0; i < SIDTAB_SIZE; i++) + s->htable[i] = NULL; + s->nel = 0; + out: + return rc; +} + +int sidtab_insert(struct sidtab *s, const char * ctx) +{ + int hvalue, rc = 0; + struct sidtab_node *newnode; + char * newctx; + + newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode)); + if (!newnode) { + rc = -1; + goto out; + } + newctx = (char *) strdup(ctx); + if (!newctx) { + rc = -1; + avc_free(newnode); + goto out; + } + + hvalue = sidtab_hash(newctx); + newnode->next = s->htable[hvalue]; + newnode->sid_s.ctx = newctx; + newnode->sid_s.refcnt = 1; /* unused */ + s->htable[hvalue] = newnode; + s->nel++; + out: + return rc; +} + +int +sidtab_context_to_sid(struct sidtab *s, + const char * ctx, security_id_t * sid) +{ + int hvalue, rc = 0; + struct sidtab_node *cur; + + if (! ctx) { + errno=EINVAL; + return -1; + } + + *sid = NULL; + hvalue = sidtab_hash(ctx); + + loop: + cur = s->htable[hvalue]; + while (cur != NULL && strcmp(cur->sid_s.ctx, ctx)) + cur = cur->next; + + if (cur == NULL) { /* need to make a new entry */ + rc = sidtab_insert(s, ctx); + if (rc) + goto out; + goto loop; /* find the newly inserted node */ + } + + *sid = &cur->sid_s; + out: + return rc; +} + +void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen) +{ + int i, chain_len, slots_used, max_chain_len; + struct sidtab_node *cur; + + slots_used = 0; + max_chain_len = 0; + for (i = 0; i < SIDTAB_SIZE; i++) { + cur = h->htable[i]; + if (cur) { + slots_used++; + chain_len = 0; + while (cur) { + chain_len++; + cur = cur->next; + } + + if (chain_len > max_chain_len) + max_chain_len = chain_len; + } + } + + snprintf(buf, buflen, + "%s: %u SID entries and %d/%d buckets used, longest " + "chain length %d\n", avc_prefix, h->nel, slots_used, + SIDTAB_SIZE, max_chain_len); +} + +void sidtab_destroy(struct sidtab *s) +{ + int i; + struct sidtab_node *cur, *temp; + + if (!s) + return; + + for (i = 0; i < SIDTAB_SIZE; i++) { + cur = s->htable[i]; + while (cur != NULL) { + temp = cur; + cur = cur->next; + freecon(temp->sid_s.ctx); + avc_free(temp); + } + s->htable[i] = NULL; + } + avc_free(s->htable); + s->htable = NULL; +} diff --git a/src/avc_sidtab.h b/src/avc_sidtab.h new file mode 100644 index 0000000..bce9b87 --- /dev/null +++ b/src/avc_sidtab.h @@ -0,0 +1,36 @@ +/* + * A security identifier table (sidtab) is a hash table + * of security context structures indexed by SID value. + */ +#ifndef _SELINUX_AVC_SIDTAB_H_ +#define _SELINUX_AVC_SIDTAB_H_ + +#include +#include +#include "dso.h" + +struct sidtab_node { + struct security_id sid_s; + struct sidtab_node *next; +}; + +#define SIDTAB_HASH_BITS 7 +#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) +#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) +#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS + +struct sidtab { + struct sidtab_node **htable; + unsigned nel; +}; + +int sidtab_init(struct sidtab *s) hidden; +int sidtab_insert(struct sidtab *s, const char * ctx) hidden; + +int sidtab_context_to_sid(struct sidtab *s, + const char * ctx, security_id_t * sid) hidden; + +void sidtab_sid_stats(struct sidtab *s, char *buf, int buflen) hidden; +void sidtab_destroy(struct sidtab *s) hidden; + +#endif /* _SELINUX_AVC_SIDTAB_H_ */ diff --git a/src/booleans.c b/src/booleans.c new file mode 100644 index 0000000..a6d46fe --- /dev/null +++ b/src/booleans.c @@ -0,0 +1,632 @@ +/* + * Author: Karl MacMillan + * + * Modified: + * Dan Walsh - Added security_load_booleans(). + */ + +#ifndef DISABLE_BOOL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "selinux_internal.h" +#include "policy.h" + +#define SELINUX_BOOL_DIR "/booleans/" + +static int filename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + return 0; + return 1; +} + +int security_get_boolean_names(char ***names, int *len) +{ + char path[PATH_MAX]; + int i, rc; + struct dirent **namelist; + char **n; + + if (!len || names == NULL) { + errno = EINVAL; + return -1; + } + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR); + *len = scandir(path, &namelist, &filename_select, alphasort); + if (*len <= 0) { + errno = ENOENT; + return -1; + } + + n = (char **)malloc(sizeof(char *) * *len); + if (!n) { + rc = -1; + goto bad; + } + + for (i = 0; i < *len; i++) { + n[i] = strdup(namelist[i]->d_name); + if (!n[i]) { + rc = -1; + goto bad_freen; + } + } + rc = 0; + *names = n; + out: + for (i = 0; i < *len; i++) { + free(namelist[i]); + } + free(namelist); + return rc; + bad_freen: + for (--i; i >= 0; --i) + free(n[i]); + free(n); + bad: + goto out; +} + +char *selinux_boolean_sub(const char *name) +{ + char *sub = NULL; + char *line_buf = NULL; + size_t line_len; + FILE *cfg; + + if (!name) + return NULL; + + cfg = fopen(selinux_booleans_subs_path(), "re"); + if (!cfg) + goto out; + + while (getline(&line_buf, &line_len, cfg) != -1) { + char *ptr; + char *src = line_buf; + char *dst; + while (*src && isspace(*src)) + src++; + if (!*src) + continue; + if (src[0] == '#') + continue; + + ptr = src; + while (*ptr && !isspace(*ptr)) + ptr++; + *ptr++ = '\0'; + if (strcmp(src, name) != 0) + continue; + + dst = ptr; + while (*dst && isspace(*dst)) + dst++; + if (!*dst) + continue; + ptr=dst; + while (*ptr && !isspace(*ptr)) + ptr++; + *ptr='\0'; + + sub = strdup(dst); + + break; + } + free(line_buf); + fclose(cfg); +out: + if (!sub) + sub = strdup(name); + return sub; +} + +static int bool_open(const char *name, int flag) { + char *fname = NULL; + char *alt_name = NULL; + int len; + int fd = -1; + int ret; + char *ptr; + + if (!name) { + errno = EINVAL; + return -1; + } + + /* note the 'sizeof' gets us enough room for the '\0' */ + len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); + fname = malloc(sizeof(char) * len); + if (!fname) + return -1; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); + if (ret < 0) + goto out; + assert(ret < len); + + fd = open(fname, flag); + if (fd >= 0 || errno != ENOENT) + goto out; + + alt_name = selinux_boolean_sub(name); + if (!alt_name) + goto out; + + /* note the 'sizeof' gets us enough room for the '\0' */ + len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); + ptr = realloc(fname, len); + if (!ptr) + goto out; + fname = ptr; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); + if (ret < 0) + goto out; + assert(ret < len); + + fd = open(fname, flag); +out: + free(fname); + free(alt_name); + + return fd; +} + +#define STRBUF_SIZE 3 +static int get_bool_value(const char *name, char **buf) +{ + int fd, len; + int errno_tmp; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1)); + if (!*buf) + return -1; + + (*buf)[STRBUF_SIZE] = 0; + + fd = bool_open(name, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto out_err; + + len = read(fd, *buf, STRBUF_SIZE); + errno_tmp = errno; + close(fd); + errno = errno_tmp; + if (len != STRBUF_SIZE) + goto out_err; + + return 0; +out_err: + free(*buf); + return -1; +} + +int security_get_boolean_pending(const char *name) +{ + char *buf; + int val; + + if (get_bool_value(name, &buf)) + return -1; + + if (atoi(&buf[1])) + val = 1; + else + val = 0; + free(buf); + return val; +} + +int security_get_boolean_active(const char *name) +{ + char *buf; + int val; + + if (get_bool_value(name, &buf)) + return -1; + + buf[1] = '\0'; + if (atoi(buf)) + val = 1; + else + val = 0; + free(buf); + return val; +} + +int security_set_boolean(const char *name, int value) +{ + int fd, ret; + char buf[2]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + if (value < 0 || value > 1) { + errno = EINVAL; + return -1; + } + + fd = bool_open(name, O_WRONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + if (value) + buf[0] = '1'; + else + buf[0] = '0'; + buf[1] = '\0'; + + ret = write(fd, buf, 2); + close(fd); + + if (ret > 0) + return 0; + else + return -1; +} + +int security_commit_booleans(void) +{ + int fd, ret; + char buf[2]; + char path[PATH_MAX]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt); + fd = open(path, O_WRONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + buf[0] = '1'; + buf[1] = '\0'; + + ret = write(fd, buf, 2); + close(fd); + + if (ret > 0) + return 0; + else + return -1; +} + +static char *strtrim(char *dest, char *source, int size) +{ + int i = 0; + char *ptr = source; + i = 0; + while (isspace(*ptr) && i < size) { + ptr++; + i++; + } + strncpy(dest, ptr, size); + for (i = strlen(dest) - 1; i > 0; i--) { + if (!isspace(dest[i])) + break; + } + dest[i + 1] = '\0'; + return dest; +} +static int process_boolean(char *buffer, char *name, int namesize, int *val) +{ + char name1[BUFSIZ]; + char *ptr = NULL; + char *tok; + + /* Skip spaces */ + while (isspace(buffer[0])) + buffer++; + /* Ignore comments */ + if (buffer[0] == '#') + return 0; + + tok = strtok_r(buffer, "=", &ptr); + if (!tok) { + errno = EINVAL; + return -1; + } + strncpy(name1, tok, BUFSIZ - 1); + strtrim(name, name1, namesize - 1); + + tok = strtok_r(NULL, "\0", &ptr); + if (!tok) { + errno = EINVAL; + return -1; + } + + while (isspace(*tok)) + tok++; + + *val = -1; + if (isdigit(tok[0])) + *val = atoi(tok); + else if (!strncasecmp(tok, "true", sizeof("true") - 1)) + *val = 1; + else if (!strncasecmp(tok, "false", sizeof("false") - 1)) + *val = 0; + if (*val != 0 && *val != 1) { + errno = EINVAL; + return -1; + } + return 1; +} +static int save_booleans(size_t boolcnt, SELboolean * boollist) +{ + ssize_t len; + size_t i; + char outbuf[BUFSIZ]; + char *inbuf = NULL; + + /* Open file */ + const char *bool_file = selinux_booleans_path(); + char local_bool_file[PATH_MAX]; + char tmp_bool_file[PATH_MAX]; + FILE *boolf; + int fd; + int *used = (int *)malloc(sizeof(int) * boolcnt); + if (!used) { + return -1; + } + /* zero out used field */ + for (i = 0; i < boolcnt; i++) + used[i] = 0; + + snprintf(tmp_bool_file, sizeof(tmp_bool_file), "%s.XXXXXX", bool_file); + fd = mkstemp(tmp_bool_file); + if (fd < 0) { + free(used); + return -1; + } + + snprintf(local_bool_file, sizeof(local_bool_file), "%s.local", + bool_file); + boolf = fopen(local_bool_file, "re"); + if (boolf != NULL) { + ssize_t ret; + size_t size = 0; + int val; + char boolname[BUFSIZ-3]; + char *buffer; + inbuf = NULL; + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while ((len = getline(&inbuf, &size, boolf)) > 0) { + buffer = strdup(inbuf); + if (!buffer) + goto close_remove_fail; + ret = + process_boolean(inbuf, boolname, sizeof(boolname), + &val); + if (ret != 1) { + ret = write(fd, buffer, len); + free(buffer); + if (ret != len) + goto close_remove_fail; + } else { + free(buffer); + for (i = 0; i < boolcnt; i++) { + if (strcmp(boollist[i].name, boolname) + == 0) { + snprintf(outbuf, sizeof(outbuf), + "%s=%d\n", boolname, + boollist[i].value); + len = strlen(outbuf); + used[i] = 1; + if (write(fd, outbuf, len) != + len) + goto close_remove_fail; + else + break; + } + } + if (i == boolcnt) { + val = !!val; + snprintf(outbuf, sizeof(outbuf), + "%s=%d\n", boolname, val); + len = strlen(outbuf); + if (write(fd, outbuf, len) != len) + goto close_remove_fail; + } + } + free(inbuf); + inbuf = NULL; + } + fclose(boolf); + } + + for (i = 0; i < boolcnt; i++) { + if (used[i] == 0) { + snprintf(outbuf, sizeof(outbuf), "%s=%d\n", + boollist[i].name, boollist[i].value); + len = strlen(outbuf); + if (write(fd, outbuf, len) != len) { + close_remove_fail: + free(inbuf); + close(fd); + remove_fail: + unlink(tmp_bool_file); + free(used); + return -1; + } + } + + } + if (fchmod(fd, S_IRUSR | S_IWUSR) != 0) + goto close_remove_fail; + close(fd); + if (rename(tmp_bool_file, local_bool_file) != 0) + goto remove_fail; + + free(used); + return 0; +} +static void rollback(SELboolean * boollist, int end) +{ + int i; + + for (i = 0; i < end; i++) + security_set_boolean(boollist[i].name, + security_get_boolean_active(boollist[i]. + name)); +} + +int security_set_boolean_list(size_t boolcnt, SELboolean * boollist, + int permanent) +{ + + size_t i; + for (i = 0; i < boolcnt; i++) { + boollist[i].value = !!boollist[i].value; + if (security_set_boolean(boollist[i].name, boollist[i].value)) { + rollback(boollist, i); + return -1; + } + } + + /* OK, let's do the commit */ + if (security_commit_booleans()) { + return -1; + } + + if (permanent) + return save_booleans(boolcnt, boollist); + + return 0; +} +int security_load_booleans(char *path) +{ + FILE *boolf; + char *inbuf; + char localbools[BUFSIZ]; + size_t len = 0, errors = 0; + int val; + char name[BUFSIZ]; + + boolf = fopen(path ? path : selinux_booleans_path(), "re"); + if (boolf == NULL) + goto localbool; + + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while (getline(&inbuf, &len, boolf) > 0) { + int ret = process_boolean(inbuf, name, sizeof(name), &val); + if (ret == -1) + errors++; + if (ret == 1) + if (security_set_boolean(name, val) < 0) { + errors++; + } + } + fclose(boolf); + localbool: + snprintf(localbools, sizeof(localbools), "%s.local", + (path ? path : selinux_booleans_path())); + boolf = fopen(localbools, "re"); + + if (boolf != NULL) { + int ret; + __fsetlocking(boolf, FSETLOCKING_BYCALLER); + while (getline(&inbuf, &len, boolf) > 0) { + ret = process_boolean(inbuf, name, sizeof(name), &val); + if (ret == -1) + errors++; + if (ret == 1) + if (security_set_boolean(name, val) < 0) { + errors++; + } + } + fclose(boolf); + } + if (security_commit_booleans() < 0) + return -1; + + if (errors) + errno = EINVAL; + return errors ? -1 : 0; +} + +#else + +#include +#include "selinux_internal.h" + +int security_set_boolean_list(size_t boolcnt __attribute__((unused)), + SELboolean * boollist __attribute__((unused)), + int permanent __attribute__((unused))) +{ + return -1; +} + +int security_load_booleans(char *path __attribute__((unused))) +{ + return -1; +} + +int security_get_boolean_names(char ***names __attribute__((unused)), + int *len __attribute__((unused))) +{ + return -1; +} + +int security_get_boolean_pending(const char *name __attribute__((unused))) +{ + return -1; +} + +int security_get_boolean_active(const char *name __attribute__((unused))) +{ + return -1; +} + +int security_set_boolean(const char *name __attribute__((unused)), + int value __attribute__((unused))) +{ + return -1; +} + +int security_commit_booleans(void) +{ + return -1; +} + +char *selinux_boolean_sub(const char *name __attribute__((unused))) +{ + return NULL; +} +#endif + +hidden_def(security_get_boolean_names) +hidden_def(selinux_boolean_sub) +hidden_def(security_get_boolean_active) +hidden_def(security_set_boolean) +hidden_def(security_commit_booleans) diff --git a/src/callbacks.c b/src/callbacks.c new file mode 100644 index 0000000..c18ccc5 --- /dev/null +++ b/src/callbacks.c @@ -0,0 +1,129 @@ +/* + * User-supplied callbacks and default implementations. + * Class and permission mappings. + */ + +#include +#include +#include +#include +#include +#include "callbacks.h" + +/* default implementations */ +static int __attribute__ ((format(printf, 2, 3))) +default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) +{ + int rc; + va_list ap; + va_start(ap, fmt); + rc = vfprintf(stderr, fmt, ap); + va_end(ap); + return rc; +} + +static int +default_selinux_audit(void *ptr __attribute__((unused)), + security_class_t cls __attribute__((unused)), + char *buf __attribute__((unused)), + size_t len __attribute__((unused))) +{ + return 0; +} + +static int +default_selinux_validate(char **ctx) +{ +#ifndef BUILD_HOST + return security_check_context(*ctx); +#else + (void) ctx; + return 0; +#endif +} + +static int +default_selinux_setenforce(int enforcing __attribute__((unused))) +{ + return 0; +} + +static int +default_selinux_policyload(int seqno __attribute__((unused))) +{ + return 0; +} + +/* callback pointers */ +int __attribute__ ((format(printf, 2, 3))) +(*selinux_log)(int, const char *, ...) = + default_selinux_log; + +int +(*selinux_audit) (void *, security_class_t, char *, size_t) = + default_selinux_audit; + +int +(*selinux_validate)(char **ctx) = + default_selinux_validate; + +int +(*selinux_netlink_setenforce) (int enforcing) = + default_selinux_setenforce; + +int +(*selinux_netlink_policyload) (int seqno) = + default_selinux_policyload; + +/* callback setting function */ +void +selinux_set_callback(int type, union selinux_callback cb) +{ + switch (type) { + case SELINUX_CB_LOG: + selinux_log = cb.func_log; + break; + case SELINUX_CB_AUDIT: + selinux_audit = cb.func_audit; + break; + case SELINUX_CB_VALIDATE: + selinux_validate = cb.func_validate; + break; + case SELINUX_CB_SETENFORCE: + selinux_netlink_setenforce = cb.func_setenforce; + break; + case SELINUX_CB_POLICYLOAD: + selinux_netlink_policyload = cb.func_policyload; + break; + } +} + +/* callback getting function */ +union selinux_callback +selinux_get_callback(int type) +{ + union selinux_callback cb; + + switch (type) { + case SELINUX_CB_LOG: + cb.func_log = selinux_log; + break; + case SELINUX_CB_AUDIT: + cb.func_audit = selinux_audit; + break; + case SELINUX_CB_VALIDATE: + cb.func_validate = selinux_validate; + break; + case SELINUX_CB_SETENFORCE: + cb.func_setenforce = selinux_netlink_setenforce; + break; + case SELINUX_CB_POLICYLOAD: + cb.func_policyload = selinux_netlink_policyload; + break; + default: + memset(&cb, 0, sizeof(cb)); + errno = EINVAL; + break; + } + return cb; +} diff --git a/src/callbacks.h b/src/callbacks.h new file mode 100644 index 0000000..2a572e0 --- /dev/null +++ b/src/callbacks.h @@ -0,0 +1,30 @@ +/* + * This file describes the callbacks passed to selinux_init() and available + * for use from the library code. They all have default implementations. + */ +#ifndef _SELINUX_CALLBACKS_H_ +#define _SELINUX_CALLBACKS_H_ + +#include +#include +#include +#include +#include "dso.h" + +/* callback pointers */ +extern int __attribute__ ((format(printf, 2, 3))) +(*selinux_log) (int type, const char *, ...) hidden; + +extern int +(*selinux_audit) (void *, security_class_t, char *, size_t) hidden; + +extern int +(*selinux_validate)(char **ctx) hidden; + +extern int +(*selinux_netlink_setenforce) (int enforcing) hidden; + +extern int +(*selinux_netlink_policyload) (int seqno) hidden; + +#endif /* _SELINUX_CALLBACKS_H_ */ diff --git a/src/canonicalize_context.c b/src/canonicalize_context.c new file mode 100644 index 0000000..c815872 --- /dev/null +++ b/src/canonicalize_context.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include + +int security_canonicalize_context_raw(const char * con, + char ** canoncon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (! con) { + errno=EINVAL; + return -1; + } + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/context", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + strncpy(buf, con, size); + + ret = write(fd, buf, strlen(buf) + 1); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0 && errno == EINVAL) { + /* Fall back to the original context for kernels + that do not support the extended interface. */ + strncpy(buf, con, size); + } + + *canoncon = strdup(buf); + if (!(*canoncon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_canonicalize_context_raw) + +int security_canonicalize_context(const char * con, + char ** canoncon) +{ + int ret; + char * rcon; + char * rcanoncon; + + if (selinux_trans_to_raw_context(con, &rcon)) + return -1; + + ret = security_canonicalize_context_raw(rcon, &rcanoncon); + + freecon(rcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rcanoncon, canoncon); + freecon(rcanoncon); + } + + return ret; +} + +hidden_def(security_canonicalize_context) diff --git a/src/checkAccess.c b/src/checkAccess.c new file mode 100644 index 0000000..16bfcfb --- /dev/null +++ b/src/checkAccess.c @@ -0,0 +1,120 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#include +#include +#include +#include +#include "selinux_internal.h" +#include +#include "avc_internal.h" + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static int selinux_enabled; + +static int avc_reset_callback(uint32_t event __attribute__((unused)), + security_id_t ssid __attribute__((unused)), + security_id_t tsid __attribute__((unused)), + security_class_t tclass __attribute__((unused)), + access_vector_t perms __attribute__((unused)), + access_vector_t *out_retained __attribute__((unused))) +{ + flush_class_cache(); + return 0; +} + +static void avc_init_once(void) +{ + selinux_enabled = is_selinux_enabled(); + if (selinux_enabled == 1) { + if (avc_open(NULL, 0)) + return; + avc_add_callback(avc_reset_callback, AVC_CALLBACK_RESET, + 0, 0, 0, 0); + } +} + +int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) { + int rc; + security_id_t scon_id; + security_id_t tcon_id; + security_class_t sclass; + access_vector_t av; + + __selinux_once(once, avc_init_once); + + if (selinux_enabled != 1) + return 0; + + rc = avc_context_to_sid(scon, &scon_id); + if (rc < 0) + return rc; + + rc = avc_context_to_sid(tcon, &tcon_id); + if (rc < 0) + return rc; + + (void) avc_netlink_check_nb(); + + sclass = string_to_security_class(class); + if (sclass == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown class %s", class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + av = string_to_av_perm(sclass, perm); + if (av == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", perm, class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); +} + +int selinux_check_passwd_access(access_vector_t requested) +{ + int status = -1; + char *user_context; + if (is_selinux_enabled() == 0) + return 0; + if (getprevcon_raw(&user_context) == 0) { + security_class_t passwd_class; + struct av_decision avd; + int retval; + + passwd_class = string_to_security_class("passwd"); + if (passwd_class == 0) { + freecon(user_context); + return 0; + } + + retval = security_compute_av_raw(user_context, + user_context, + passwd_class, + requested, + &avd); + + if ((retval == 0) && ((requested & avd.allowed) == requested)) { + status = 0; + } + freecon(user_context); + } + + if (status != 0 && security_getenforce() == 0) + status = 0; + + return status; +} + +hidden_def(selinux_check_passwd_access) + +int checkPasswdAccess(access_vector_t requested) +{ + return selinux_check_passwd_access(requested); +} diff --git a/src/check_context.c b/src/check_context.c new file mode 100644 index 0000000..5be8434 --- /dev/null +++ b/src/check_context.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include + +int security_check_context_raw(const char * con) +{ + char path[PATH_MAX]; + int fd, ret; + + if (! con) { + errno=EINVAL; + return -1; + } + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/context", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + ret = write(fd, con, strlen(con) + 1); + close(fd); + if (ret < 0) + return -1; + return 0; +} + +hidden_def(security_check_context_raw) + +int security_check_context(const char * con) +{ + int ret; + char * rcon; + + if (selinux_trans_to_raw_context(con, &rcon)) + return -1; + + ret = security_check_context_raw(rcon); + + freecon(rcon); + + return ret; +} + +hidden_def(security_check_context) diff --git a/src/checkreqprot.c b/src/checkreqprot.c new file mode 100644 index 0000000..9b4b12d --- /dev/null +++ b/src/checkreqprot.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_get_checkreqprot(void) +{ + int fd, ret, checkreqprot = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof(path), "%s/checkreqprot", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &checkreqprot) != 1) + return -1; + + return checkreqprot; +} + +hidden_def(security_get_checkreqprot); diff --git a/src/compute_av.c b/src/compute_av.c new file mode 100644 index 0000000..6d285a2 --- /dev/null +++ b/src/compute_av.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_av_flags_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + char path[PATH_MAX]; + char *buf; + size_t len; + int fd, ret; + security_class_t kclass; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + if ((! scon) || (! tcon)) { + errno=EINVAL; + return -1; + } + + snprintf(path, sizeof path, "%s/access", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + len = selinux_page_size; + buf = malloc(len); + if (!buf) { + ret = -1; + goto out; + } + + kclass = unmap_class(tclass); + snprintf(buf, len, "%s %s %hu %x", scon, tcon, + kclass, unmap_perm(tclass, requested)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, len); + ret = read(fd, buf, len - 1); + if (ret < 0) + goto out2; + + ret = sscanf(buf, "%x %x %x %x %u %x", + &avd->allowed, &avd->decided, + &avd->auditallow, &avd->auditdeny, + &avd->seqno, &avd->flags); + if (ret < 5) { + ret = -1; + goto out2; + } else if (ret < 6) + avd->flags = 0; + + /* + * If the tclass could not be mapped to a kernel class at all, the + * kernel will have already set avd according to the + * handle_unknown flag and we do not need to do anything further. + * Otherwise, we must map the permissions within the returned + * avd to the userspace permission values. + */ + if (kclass != 0) + map_decision(tclass, avd); + + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_av_flags_raw) + +int security_compute_av_raw(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags_raw(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + return ret; +} + +hidden_def(security_compute_av_raw) + +int security_compute_av_flags(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, + struct av_decision *avd) +{ + char * rscon; + char * rtcon; + int ret; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + ret = security_compute_av_flags_raw(rscon, rtcon, tclass, + requested, avd); + + freecon(rscon); + freecon(rtcon); + + return ret; +} + +hidden_def(security_compute_av_flags) + +int security_compute_av(const char * scon, + const char * tcon, + security_class_t tclass, + access_vector_t requested, struct av_decision *avd) +{ + struct av_decision lavd; + int ret; + + ret = security_compute_av_flags(scon, tcon, tclass, + requested, &lavd); + if (ret == 0) + { + avd->allowed = lavd.allowed; + avd->decided = lavd.decided; + avd->auditallow = lavd.auditallow; + avd->auditdeny = lavd.auditdeny; + avd->seqno = lavd.seqno; + /* NOTE: + * We should not return avd->flags via the interface + * due to the binary compatibility. + */ + } + + return ret; +} + +hidden_def(security_compute_av) diff --git a/src/compute_create.c b/src/compute_create.c new file mode 100644 index 0000000..3e6a48c --- /dev/null +++ b/src/compute_create.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +static int object_name_encode(const char *objname, char *buffer, size_t buflen) +{ + int code; + size_t offset = 0; + + if (buflen - offset < 1) + return -1; + buffer[offset++] = ' '; + + do { + code = *objname++; + + if (isalnum(code) || code == '\0' || code == '-' || + code == '.' || code == '_' || code == '~') { + if (buflen - offset < 1) + return -1; + buffer[offset++] = code; + } else if (code == ' ') { + if (buflen - offset < 1) + return -1; + buffer[offset++] = '+'; + } else { + static const char *table = "0123456789ABCDEF"; + int l = (code & 0x0f); + int h = (code & 0xf0) >> 4; + + if (buflen - offset < 3) + return -1; + buffer[offset++] = '%'; + buffer[offset++] = table[h]; + buffer[offset++] = table[l]; + } + } while (code != '\0'); + + return 0; +} + +int security_compute_create_name_raw(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret, len; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + if ((! scon) || (! tcon)) { + errno=EINVAL; + return -1; + } + + snprintf(path, sizeof path, "%s/create", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + len = snprintf(buf, size, "%s %s %hu", + scon, tcon, unmap_class(tclass)); + if (objname && + object_name_encode(objname, buf + len, size - len) < 0) { + errno = ENAMETOOLONG; + ret = -1; + goto out2; + } + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!(*newcon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} +hidden_def(security_compute_create_name_raw) + +int security_compute_create_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + return security_compute_create_name_raw(scon, tcon, tclass, + NULL, newcon); +} +hidden_def(security_compute_create_raw) + +int security_compute_create_name(const char * scon, + const char * tcon, + security_class_t tclass, + const char *objname, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_create_name_raw(rscon, rtcon, tclass, + objname, &rnewcon); + freecon(rscon); + freecon(rtcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rnewcon, newcon); + freecon(rnewcon); + } + + return ret; +} +hidden_def(security_compute_create_name) + +int security_compute_create(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + return security_compute_create_name(scon, tcon, tclass, NULL, newcon); +} +hidden_def(security_compute_create) diff --git a/src/compute_member.c b/src/compute_member.c new file mode 100644 index 0000000..d1dd977 --- /dev/null +++ b/src/compute_member.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_member_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + if ((! scon) || (! tcon)) { + errno=EINVAL; + return -1; + } + + snprintf(path, sizeof path, "%s/member", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!(*newcon)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_member_raw) + +int security_compute_member(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_member_raw(rscon, rtcon, tclass, &rnewcon); + + freecon(rscon); + freecon(rtcon); + if (!ret) { + if (selinux_raw_to_trans_context(rnewcon, newcon)) { + *newcon = NULL; + ret = -1; + } + freecon(rnewcon); + } + + return ret; +} diff --git a/src/compute_relabel.c b/src/compute_relabel.c new file mode 100644 index 0000000..c3db7c0 --- /dev/null +++ b/src/compute_relabel.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +int security_compute_relabel_raw(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + if ((! scon) || (! tcon)) { + errno=EINVAL; + return -1; + } + + snprintf(path, sizeof path, "%s/relabel", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass)); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *newcon = strdup(buf); + if (!*newcon) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_relabel_raw) + +int security_compute_relabel(const char * scon, + const char * tcon, + security_class_t tclass, + char ** newcon) +{ + int ret; + char * rscon; + char * rtcon; + char * rnewcon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + if (selinux_trans_to_raw_context(tcon, &rtcon)) { + freecon(rscon); + return -1; + } + + ret = security_compute_relabel_raw(rscon, rtcon, tclass, &rnewcon); + + freecon(rscon); + freecon(rtcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rnewcon, newcon); + freecon(rnewcon); + } + + return ret; +} diff --git a/src/compute_user.c b/src/compute_user.c new file mode 100644 index 0000000..401fd10 --- /dev/null +++ b/src/compute_user.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include + +int security_compute_user_raw(const char * scon, + const char *user, char *** con) +{ + char path[PATH_MAX]; + char **ary; + char *buf, *ptr; + size_t size; + int fd, ret; + unsigned int i, nel; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + if (! scon) { + errno=EINVAL; + return -1; + } + + snprintf(path, sizeof path, "%s/user", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + snprintf(buf, size, "%s %s", scon, user); + + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + goto out2; + + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + if (sscanf(buf, "%u", &nel) != 1) { + ret = -1; + goto out2; + } + + ary = malloc((nel + 1) * sizeof(char *)); + if (!ary) { + ret = -1; + goto out2; + } + + ptr = buf + strlen(buf) + 1; + for (i = 0; i < nel; i++) { + ary[i] = strdup(ptr); + if (!ary[i]) { + freeconary(ary); + ret = -1; + goto out2; + } + ptr += strlen(ptr) + 1; + } + ary[nel] = NULL; + *con = ary; + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_compute_user_raw) + +int security_compute_user(const char * scon, + const char *user, char *** con) +{ + int ret; + char * rscon; + + if (selinux_trans_to_raw_context(scon, &rscon)) + return -1; + + ret = security_compute_user_raw(rscon, user, con); + + freecon(rscon); + if (!ret) { + char **ptr, *tmpcon; + for (ptr = *con; *ptr; ptr++) { + if (selinux_raw_to_trans_context(*ptr, &tmpcon)) { + freeconary(*con); + *con = NULL; + return -1; + } + freecon(*ptr); + *ptr = tmpcon; + } + } + + return ret; +} + +hidden_def(security_compute_user) diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..b673733 --- /dev/null +++ b/src/context.c @@ -0,0 +1,195 @@ +#include "context_internal.h" +#include +#include +#include +#include + +#define COMP_USER 0 +#define COMP_ROLE 1 +#define COMP_TYPE 2 +#define COMP_RANGE 3 + +typedef struct { + char *current_str; /* This is made up-to-date only when needed */ + char *(component[4]); +} context_private_t; + +/* + * Allocate a new context, initialized from str. There must be 3 or + * 4 colon-separated components and no whitespace in any component other + * than the MLS component. + */ +context_t context_new(const char *str) +{ + int i, count; + errno = 0; + context_private_t *n = + (context_private_t *) malloc(sizeof(context_private_t)); + context_t result = (context_t) malloc(sizeof(context_s_t)); + const char *p, *tok; + + if (result) + result->ptr = n; + else + free(n); + if (n == 0 || result == 0) { + goto err; + } + n->current_str = n->component[0] = n->component[1] = n->component[2] = + n->component[3] = 0; + for (i = count = 0, p = str; *p; p++) { + switch (*p) { + case ':': + count++; + break; + case '\n': + case '\t': + case '\r': + goto err; /* sanity check */ + case ' ': + if (count < 3) + goto err; /* sanity check */ + } + } + /* + * Could be anywhere from 2 - 5 + * e.g user:role:type to user:role:type:sens1:cata-sens2:catb + */ + if (count < 2 || count > 5) { /* might not have a range */ + goto err; + } + + n->component[3] = 0; + for (i = 0, tok = str; *tok; i++) { + if (i < 3) + for (p = tok; *p && *p != ':'; p++) { /* empty */ + } else { + /* MLS range is one component */ + for (p = tok; *p; p++) { /* empty */ + } + } + n->component[i] = (char *)malloc(p - tok + 1); + if (n->component[i] == 0) + goto err; + strncpy(n->component[i], tok, p - tok); + n->component[i][p - tok] = '\0'; + tok = *p ? p + 1 : p; + } + return result; + err: + if (errno == 0) errno = EINVAL; + context_free(result); + return 0; +} + +hidden_def(context_new) + +static void conditional_free(char **v) +{ + if (*v) { + free(*v); + } + *v = 0; +} + +/* + * free all storage used by a context. Safe to call with + * null pointer. + */ +void context_free(context_t context) +{ + context_private_t *n; + int i; + if (context) { + n = context->ptr; + if (n) { + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + conditional_free(&n->component[i]); + } + free(n); + } + free(context); + } +} + +hidden_def(context_free) + +/* + * Return a pointer to the string value of the context. + */ +char *context_str(context_t context) +{ + context_private_t *n = context->ptr; + int i; + size_t total = 0; + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + if (n->component[i]) { + total += strlen(n->component[i]) + 1; + } + } + n->current_str = malloc(total); + if (n->current_str != 0) { + char *cp = n->current_str; + + cp = stpcpy(cp, n->component[0]); + for (i = 1; i < 4; i++) { + if (n->component[i]) { + *cp++ = ':'; + cp = stpcpy(cp, n->component[i]); + } + } + } + return n->current_str; +} + +hidden_def(context_str) + +/* Returns nonzero iff failed */ +static int set_comp(context_private_t * n, int idx, const char *str) +{ + char *t = NULL; + const char *p; + if (str) { + t = (char *)malloc(strlen(str) + 1); + if (!t) { + return 1; + } + for (p = str; *p; p++) { + if (*p == '\t' || *p == '\n' || *p == '\r' || + ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { + free(t); + errno = EINVAL; + return 1; + } + } + strcpy(t, str); + } + conditional_free(&n->component[idx]); + n->component[idx] = t; + return 0; +} + +#define def_get(name,tag) \ +const char * context_ ## name ## _get(context_t context) \ +{ \ + context_private_t *n = context->ptr; \ + return n->component[tag]; \ +} \ +hidden_def(context_ ## name ## _get) + +def_get(type, COMP_TYPE) + def_get(user, COMP_USER) + def_get(range, COMP_RANGE) + def_get(role, COMP_ROLE) +#define def_set(name,tag) \ +int context_ ## name ## _set(context_t context, const char* str) \ +{ \ + return set_comp(context->ptr,tag,str);\ +} \ +hidden_def(context_ ## name ## _set) + def_set(type, COMP_TYPE) + def_set(role, COMP_ROLE) + def_set(user, COMP_USER) + def_set(range, COMP_RANGE) diff --git a/src/context_internal.h b/src/context_internal.h new file mode 100644 index 0000000..3c71e80 --- /dev/null +++ b/src/context_internal.h @@ -0,0 +1,14 @@ +#include +#include "dso.h" + +hidden_proto(context_new) + hidden_proto(context_free) + hidden_proto(context_str) + hidden_proto(context_type_set) + hidden_proto(context_type_get) + hidden_proto(context_role_set) + hidden_proto(context_role_get) + hidden_proto(context_user_set) + hidden_proto(context_user_get) + hidden_proto(context_range_set) + hidden_proto(context_range_get) diff --git a/src/deny_unknown.c b/src/deny_unknown.c new file mode 100644 index 0000000..77d04e3 --- /dev/null +++ b/src/deny_unknown.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_deny_unknown(void) +{ + int fd, ret, deny_unknown = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof(path), "%s/deny_unknown", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &deny_unknown) != 1) + return -1; + + return deny_unknown; +} + +hidden_def(security_deny_unknown); diff --git a/src/disable.c b/src/disable.c new file mode 100644 index 0000000..8d66262 --- /dev/null +++ b/src/disable.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_disable(void) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/disable", selinux_mnt); + fd = open(path, O_WRONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + buf[0] = '1'; + buf[1] = '\0'; + ret = write(fd, buf, strlen(buf)); + close(fd); + if (ret < 0) + return -1; + + return 0; +} + +hidden_def(security_disable) diff --git a/src/dso.h b/src/dso.h new file mode 100644 index 0000000..12c3d11 --- /dev/null +++ b/src/dso.h @@ -0,0 +1,23 @@ +#ifndef _SELINUX_DSO_H +#define _SELINUX_DSO_H 1 + +#ifdef SHARED +# define hidden __attribute__ ((visibility ("hidden"))) +# define hidden_proto(fct) __hidden_proto (fct, fct##_internal) +# define __hidden_proto(fct, internal) \ + extern __typeof (fct) internal; \ + extern __typeof (fct) fct __asm (#internal) hidden; +# if defined(__alpha__) || defined(__mips__) +# define hidden_def(fct) \ + asm (".globl " #fct "\n" #fct " = " #fct "_internal"); +# else +# define hidden_def(fct) \ + asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); +#endif +#else +# define hidden +# define hidden_proto(fct) +# define hidden_def(fct) +#endif + +#endif diff --git a/src/enabled.c b/src/enabled.c new file mode 100644 index 0000000..dd628fb --- /dev/null +++ b/src/enabled.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include "selinux_internal.h" +#include +#include +#include +#include +#include "policy.h" + +int is_selinux_enabled(void) +{ + /* init_selinuxmnt() gets called before this function. We + * will assume that if a selinux file system is mounted, then + * selinux is enabled. */ +#ifdef ANDROID + return (selinux_mnt ? 1 : 0); +#else + return (selinux_mnt && has_selinux_config); +#endif +} + +hidden_def(is_selinux_enabled) + +/* + * Function: is_selinux_mls_enabled() + * Return: 1 on success + * 0 on failure + */ +int is_selinux_mls_enabled(void) +{ + char buf[20], path[PATH_MAX]; + int fd, ret, enabled = 0; + + if (!selinux_mnt) + return enabled; + + snprintf(path, sizeof path, "%s/mls", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return enabled; + + memset(buf, 0, sizeof buf); + + do { + ret = read(fd, buf, sizeof buf - 1); + } while (ret < 0 && errno == EINTR); + close(fd); + if (ret < 0) + return enabled; + + if (!strcmp(buf, "1")) + enabled = 1; + + return enabled; +} + +hidden_def(is_selinux_mls_enabled) diff --git a/src/exception.sh b/src/exception.sh new file mode 100755 index 0000000..d6c8c71 --- /dev/null +++ b/src/exception.sh @@ -0,0 +1,24 @@ +function except() { +case $1 in + selinux_file_context_cmp) # ignore + ;; + *) +echo " +%exception $1 { + \$action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + SWIG_fail; + } +} +" +;; +esac +} +if ! ${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h +then + # clang does not support -aux-info so fall back to gcc + gcc -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h +fi +for i in `awk '/.*extern int/ { print $6 }' temp.aux`; do except $i ; done +rm -f -- temp.aux -.o diff --git a/src/fgetfilecon.c b/src/fgetfilecon.c new file mode 100644 index 0000000..5522ac1 --- /dev/null +++ b/src/fgetfilecon.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +int fgetfilecon_raw(int fd, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(fgetfilecon_raw) + +int fgetfilecon(int fd, char ** context) +{ + char * rcontext = NULL; + int ret; + + *context = NULL; + + ret = fgetfilecon_raw(fd, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + if (ret >= 0 && *context) + return strlen(*context) + 1; + + return ret; +} diff --git a/src/file_path_suffixes.h b/src/file_path_suffixes.h new file mode 100644 index 0000000..2d3ca49 --- /dev/null +++ b/src/file_path_suffixes.h @@ -0,0 +1,33 @@ +/* File name suffixes. */ +S_(BINPOLICY, "/policy/policy") + S_(CONTEXTS_DIR, "/contexts") + S_(FILE_CONTEXTS, "/contexts/files/file_contexts") + S_(HOMEDIR_CONTEXTS, "/contexts/files/homedir_template") + S_(DEFAULT_CONTEXTS, "/contexts/default_contexts") + S_(USER_CONTEXTS, "/contexts/users/") + S_(FAILSAFE_CONTEXT, "/contexts/failsafe_context") + S_(DEFAULT_TYPE, "/contexts/default_type") + S_(SECURETTY_TYPES, "/contexts/securetty_types") + S_(BOOLEANS, "/booleans") + S_(MEDIA_CONTEXTS, "/contexts/files/media") + S_(REMOVABLE_CONTEXT, "/contexts/removable_context") + S_(CUSTOMIZABLE_TYPES, "/contexts/customizable_types") + S_(USERS_DIR, "/users/") + S_(SEUSERS, "/seusers") + S_(TRANSLATIONS, "/setrans.conf") + S_(NETFILTER_CONTEXTS, "/contexts/netfilter_contexts") + S_(FILE_CONTEXTS_HOMEDIR, "/contexts/files/file_contexts.homedirs") + S_(FILE_CONTEXTS_LOCAL, "/contexts/files/file_contexts.local") + S_(X_CONTEXTS, "/contexts/x_contexts") + S_(COLORS, "/secolor.conf") + S_(VIRTUAL_DOMAIN, "/contexts/virtual_domain_context") + S_(VIRTUAL_IMAGE, "/contexts/virtual_image_context") + S_(LXC_CONTEXTS, "/contexts/lxc_contexts") + S_(OPENRC_CONTEXTS, "/contexts/openrc_contexts") + S_(OPENSSH_CONTEXTS, "/contexts/openssh_contexts") + S_(SNAPPERD_CONTEXTS, "/contexts/snapperd_contexts") + S_(SYSTEMD_CONTEXTS, "/contexts/systemd_contexts") + S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs") + S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist") + S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts") + S_(BOOLEAN_SUBS, "/booleans.subs_dist") diff --git a/src/freecon.c b/src/freecon.c new file mode 100644 index 0000000..5290dfa --- /dev/null +++ b/src/freecon.c @@ -0,0 +1,11 @@ +#include +#include "selinux_internal.h" +#include +#include + +void freecon(char * con) +{ + free(con); +} + +hidden_def(freecon) diff --git a/src/freeconary.c b/src/freeconary.c new file mode 100644 index 0000000..8d07718 --- /dev/null +++ b/src/freeconary.c @@ -0,0 +1,19 @@ +#include +#include "selinux_internal.h" +#include +#include + +void freeconary(char ** con) +{ + char **ptr; + + if (!con) + return; + + for (ptr = con; *ptr; ptr++) { + free(*ptr); + } + free(con); +} + +hidden_def(freeconary) diff --git a/src/fsetfilecon.c b/src/fsetfilecon.c new file mode 100644 index 0000000..0cbe12d --- /dev/null +++ b/src/fsetfilecon.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +int fsetfilecon_raw(int fd, const char * context) +{ + int rc; + if (! context) { + errno=EINVAL; + return -1; + } + rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((fgetfilecon_raw(fd, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(fsetfilecon_raw) + +int fsetfilecon(int fd, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = fsetfilecon_raw(fd, rcontext); + + freecon(rcontext); + + return ret; +} diff --git a/src/get_context_list.c b/src/get_context_list.c new file mode 100644 index 0000000..26d7b3b --- /dev/null +++ b/src/get_context_list.c @@ -0,0 +1,500 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "context_internal.h" +#include "get_context_list_internal.h" + +int get_default_context_with_role(const char *user, + const char *role, + char * fromcon, + char ** newcon) +{ + char **conary; + char **ptr; + context_t con; + const char *role2; + int rc; + + rc = get_ordered_context_list(user, fromcon, &conary); + if (rc <= 0) + return -1; + + for (ptr = conary; *ptr; ptr++) { + con = context_new(*ptr); + if (!con) + continue; + role2 = context_role_get(con); + if (role2 && !strcmp(role, role2)) { + context_free(con); + break; + } + context_free(con); + } + + rc = -1; + if (!(*ptr)) { + errno = EINVAL; + goto out; + } + *newcon = strdup(*ptr); + if (!(*newcon)) + goto out; + rc = 0; + out: + freeconary(conary); + return rc; +} + +hidden_def(get_default_context_with_role) + +int get_default_context_with_rolelevel(const char *user, + const char *role, + const char *level, + char * fromcon, + char ** newcon) +{ + + int rc = 0; + int freefrom = 0; + context_t con; + char *newfromcon; + if (!level) + return get_default_context_with_role(user, role, fromcon, + newcon); + + if (!fromcon) { + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + rc = -1; + con = context_new(fromcon); + if (!con) + goto out; + + if (context_range_set(con, level)) + goto out; + + newfromcon = context_str(con); + if (!newfromcon) + goto out; + + rc = get_default_context_with_role(user, role, newfromcon, newcon); + + out: + context_free(con); + if (freefrom) + freecon(fromcon); + return rc; + +} + +int get_default_context(const char *user, + char * fromcon, char ** newcon) +{ + char **conary; + int rc; + + rc = get_ordered_context_list(user, fromcon, &conary); + if (rc <= 0) + return -1; + + *newcon = strdup(conary[0]); + freeconary(conary); + if (!(*newcon)) + return -1; + return 0; +} + +static int is_in_reachable(char **reachable, const char *usercon_str) +{ + if (!reachable) + return 0; + + for (; *reachable != NULL; reachable++) { + if (strcmp(*reachable, usercon_str) == 0) { + return 1; + } + } + return 0; +} + +static int get_context_user(FILE * fp, + char * fromcon, + const char * user, + char ***reachable, + unsigned int *nreachable) +{ + char *start, *end = NULL; + char *line = NULL; + size_t line_len = 0, usercon_len; + size_t user_len = strlen(user); + ssize_t len; + int found = 0; + const char *fromrole, *fromtype, *fromlevel; + char *linerole, *linetype; + char **new_reachable = NULL; + char *usercon_str; + context_t con; + context_t usercon; + + int rc; + + errno = EINVAL; + + /* Extract the role and type of the fromcon for matching. + User identity and MLS range can be variable. */ + con = context_new(fromcon); + if (!con) + return -1; + fromrole = context_role_get(con); + fromtype = context_type_get(con); + fromlevel = context_range_get(con); + if (!fromrole || !fromtype) { + context_free(con); + return -1; + } + + while ((len = getline(&line, &line_len, fp)) > 0) { + if (line[len - 1] == '\n') + line[len - 1] = 0; + + /* Skip leading whitespace. */ + start = line; + while (*start && isspace(*start)) + start++; + if (!(*start)) + continue; + + /* Find the end of the (partial) fromcon in the line. */ + end = start; + while (*end && !isspace(*end)) + end++; + if (!(*end)) + continue; + + /* Check for a match. */ + linerole = start; + while (*start && !isspace(*start) && *start != ':') + start++; + if (*start != ':') + continue; + *start = 0; + linetype = ++start; + while (*start && !isspace(*start) && *start != ':') + start++; + if (!(*start)) + continue; + *start = 0; + if (!strcmp(fromrole, linerole) && !strcmp(fromtype, linetype)) { + found = 1; + break; + } + } + + if (!found) { + errno = ENOENT; + rc = -1; + goto out; + } + + start = ++end; + while (*start) { + /* Skip leading whitespace */ + while (*start && isspace(*start)) + start++; + if (!(*start)) + break; + + /* Find the end of this partial context. */ + end = start; + while (*end && !isspace(*end)) + end++; + if (*end) + *end++ = 0; + + /* Check whether a new context is valid */ + if (SIZE_MAX - user_len < strlen(start) + 2) { + fprintf(stderr, "%s: one of partial contexts is too big\n", __FUNCTION__); + errno = EINVAL; + rc = -1; + goto out; + } + usercon_len = user_len + strlen(start) + 2; + usercon_str = malloc(usercon_len); + if (!usercon_str) { + rc = -1; + goto out; + } + + /* set range from fromcon in the new usercon */ + snprintf(usercon_str, usercon_len, "%s:%s", user, start); + usercon = context_new(usercon_str); + if (!usercon) { + if (errno != EINVAL) { + free(usercon_str); + rc = -1; + goto out; + } + fprintf(stderr, + "%s: can't create a context from %s, skipping\n", + __FUNCTION__, usercon_str); + free(usercon_str); + start = end; + continue; + } + free(usercon_str); + if (context_range_set(usercon, fromlevel) != 0) { + context_free(usercon); + rc = -1; + goto out; + } + usercon_str = context_str(usercon); + if (!usercon_str) { + context_free(usercon); + rc = -1; + goto out; + } + + /* check whether usercon is already in reachable */ + if (is_in_reachable(*reachable, usercon_str)) { + context_free(usercon); + start = end; + continue; + } + if (security_check_context(usercon_str) == 0) { + new_reachable = realloc(*reachable, (*nreachable + 2) * sizeof(char *)); + if (!new_reachable) { + context_free(usercon); + rc = -1; + goto out; + } + *reachable = new_reachable; + new_reachable[*nreachable] = strdup(usercon_str); + if (new_reachable[*nreachable] == NULL) { + context_free(usercon); + rc = -1; + goto out; + } + new_reachable[*nreachable + 1] = 0; + *nreachable += 1; + } + context_free(usercon); + start = end; + } + rc = 0; + + out: + context_free(con); + free(line); + return rc; +} + +static int get_failsafe_context(const char *user, char ** newcon) +{ + FILE *fp; + char buf[255], *ptr; + size_t plen, nlen; + int rc; + + fp = fopen(selinux_failsafe_context_path(), "re"); + if (!fp) + return -1; + + ptr = fgets_unlocked(buf, sizeof buf, fp); + fclose(fp); + + if (!ptr) + return -1; + plen = strlen(ptr); + if (buf[plen - 1] == '\n') + buf[plen - 1] = 0; + + nlen = strlen(user) + 1 + plen + 1; + *newcon = malloc(nlen); + if (!(*newcon)) + return -1; + rc = snprintf(*newcon, nlen, "%s:%s", user, ptr); + if (rc < 0 || (size_t) rc >= nlen) { + free(*newcon); + *newcon = 0; + return -1; + } + + /* If possible, check the context to catch + errors early rather than waiting until the + caller tries to use setexeccon on the context. + But this may not always be possible, e.g. if + selinuxfs isn't mounted. */ + if (security_check_context(*newcon) && errno != ENOENT) { + free(*newcon); + *newcon = 0; + return -1; + } + + return 0; +} + +int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, + char *** list) +{ + int rc; + int freefrom = 0; + context_t con; + char *newfromcon; + + if (!level) + return get_ordered_context_list(user, fromcon, list); + + if (!fromcon) { + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + rc = -1; + con = context_new(fromcon); + if (!con) + goto out; + + if (context_range_set(con, level)) + goto out; + + newfromcon = context_str(con); + if (!newfromcon) + goto out; + + rc = get_ordered_context_list(user, newfromcon, list); + + out: + context_free(con); + if (freefrom) + freecon(fromcon); + return rc; +} + +hidden_def(get_ordered_context_list_with_level) + +int get_default_context_with_level(const char *user, + const char *level, + char * fromcon, + char ** newcon) +{ + char **conary; + int rc; + + rc = get_ordered_context_list_with_level(user, level, fromcon, &conary); + if (rc <= 0) + return -1; + + *newcon = strdup(conary[0]); + freeconary(conary); + if (!(*newcon)) + return -1; + return 0; +} + +int get_ordered_context_list(const char *user, + char * fromcon, + char *** list) +{ + char **reachable = NULL; + int rc = 0; + unsigned nreachable = 0, freefrom = 0; + FILE *fp; + char *fname = NULL; + size_t fname_len; + const char *user_contexts_path = selinux_user_contexts_path(); + + if (!fromcon) { + /* Get the current context and use it for the starting context */ + rc = getcon(&fromcon); + if (rc < 0) + return rc; + freefrom = 1; + } + + /* Determine the ordering to apply from the optional per-user config + and from the global config. */ + fname_len = strlen(user_contexts_path) + strlen(user) + 2; + fname = malloc(fname_len); + if (!fname) + goto failsafe; + snprintf(fname, fname_len, "%s%s", user_contexts_path, user); + fp = fopen(fname, "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); + + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, + "%s: error in processing configuration file %s\n", + __FUNCTION__, fname); + /* Fall through, try global config */ + } + } + free(fname); + fp = fopen(selinux_default_context_path(), "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, + "%s: error in processing configuration file %s\n", + __FUNCTION__, selinux_default_context_path()); + /* Fall through */ + } + } + + if (!nreachable) + goto failsafe; + + out: + if (nreachable > 0) { + *list = reachable; + rc = nreachable; + } + else + freeconary(reachable); + + if (freefrom) + freecon(fromcon); + + return rc; + + failsafe: + /* Unable to determine a reachable context list, try to fall back to + the "failsafe" context to at least permit root login + for emergency recovery if possible. */ + freeconary(reachable); + reachable = malloc(2 * sizeof(char *)); + if (!reachable) { + rc = -1; + goto out; + } + reachable[0] = reachable[1] = 0; + rc = get_failsafe_context(user, &reachable[0]); + if (rc < 0) { + freeconary(reachable); + reachable = NULL; + goto out; + } + nreachable = 1; /* one context in the list */ + goto out; +} + +hidden_def(get_ordered_context_list) diff --git a/src/get_context_list_internal.h b/src/get_context_list_internal.h new file mode 100644 index 0000000..c224834 --- /dev/null +++ b/src/get_context_list_internal.h @@ -0,0 +1,6 @@ +#include +#include "dso.h" + +hidden_proto(get_ordered_context_list) + hidden_proto(get_ordered_context_list_with_level) + hidden_proto(get_default_context_with_role) diff --git a/src/get_default_type.c b/src/get_default_type.c new file mode 100644 index 0000000..dd7b5d7 --- /dev/null +++ b/src/get_default_type.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include "get_default_type_internal.h" +#include + +static int find_default_type(FILE * fp, const char *role, char **type); + +int get_default_type(const char *role, char **type) +{ + FILE *fp = NULL; + + fp = fopen(selinux_default_type_path(), "re"); + if (!fp) + return -1; + + if (find_default_type(fp, role, type) < 0) { + fclose(fp); + return -1; + } + + fclose(fp); + return 0; +} + +static int find_default_type(FILE * fp, const char *role, char **type) +{ + char buf[250]; + const char *ptr = "", *end; + char *t; + size_t len; + int found = 0; + + len = strlen(role); + while (!feof_unlocked(fp)) { + if (!fgets_unlocked(buf, sizeof buf, fp)) { + errno = EINVAL; + return -1; + } + if (buf[strlen(buf) - 1]) + buf[strlen(buf) - 1] = 0; + + ptr = buf; + while (*ptr && isspace(*ptr)) + ptr++; + if (!(*ptr)) + continue; + + if (!strncmp(role, ptr, len)) { + end = ptr + len; + if (*end == ':') { + found = 1; + ptr = ++end; + break; + } + } + } + + if (!found) { + errno = EINVAL; + return -1; + } + + t = malloc(strlen(buf) - len); + if (!t) + return -1; + strcpy(t, ptr); + *type = t; + return 0; +} diff --git a/src/get_default_type_internal.h b/src/get_default_type_internal.h new file mode 100644 index 0000000..0da3c51 --- /dev/null +++ b/src/get_default_type_internal.h @@ -0,0 +1,4 @@ +#include +#include "dso.h" + +hidden_proto(selinux_default_type_path) diff --git a/src/get_initial_context.c b/src/get_initial_context.c new file mode 100644 index 0000000..5e919f4 --- /dev/null +++ b/src/get_initial_context.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include + +#define SELINUX_INITCON_DIR "/initial_contexts/" + +int security_get_initial_context_raw(const char * name, char ** con) +{ + char path[PATH_MAX]; + char *buf; + size_t size; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s%s%s", + selinux_mnt, SELINUX_INITCON_DIR, name); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + memset(buf, 0, size); + ret = read(fd, buf, size - 1); + if (ret < 0) + goto out2; + + *con = strdup(buf); + if (!(*con)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + close(fd); + return ret; +} + +hidden_def(security_get_initial_context_raw) + +int security_get_initial_context(const char * name, char ** con) +{ + int ret; + char * rcon; + + ret = security_get_initial_context_raw(name, &rcon); + if (!ret) { + ret = selinux_raw_to_trans_context(rcon, con); + freecon(rcon); + } + + return ret; +} + +hidden_def(security_get_initial_context) diff --git a/src/getenforce.c b/src/getenforce.c new file mode 100644 index 0000000..d909dce --- /dev/null +++ b/src/getenforce.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_getenforce(void) +{ + int fd, ret, enforce = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/enforce", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof buf); + ret = read(fd, buf, sizeof buf - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &enforce) != 1) + return -1; + + return !!enforce; +} + +hidden_def(security_getenforce) diff --git a/src/getfilecon.c b/src/getfilecon.c new file mode 100644 index 0000000..20bee8a --- /dev/null +++ b/src/getfilecon.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include "selinux_internal.h" +#include +#include +#include +#include "policy.h" + +int getfilecon_raw(const char *path, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = getxattr(path, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(getfilecon_raw) + +int getfilecon(const char *path, char ** context) +{ + int ret; + char * rcontext = NULL; + + *context = NULL; + + ret = getfilecon_raw(path, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + if (ret >= 0 && *context) + return strlen(*context) + 1; + + return ret; +} + +hidden_def(getfilecon) diff --git a/src/getpeercon.c b/src/getpeercon.c new file mode 100644 index 0000000..3a77a2d --- /dev/null +++ b/src/getpeercon.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +#ifndef SO_PEERSEC +#define SO_PEERSEC 31 +#endif + +int getpeercon_raw(int fd, char ** context) +{ + char *buf; + socklen_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); + } + out: + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(getpeercon_raw) + +int getpeercon(int fd, char ** context) +{ + int ret; + char * rcontext; + + ret = getpeercon_raw(fd, &rcontext); + + if (!ret) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + return ret; +} diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..2690a72 --- /dev/null +++ b/src/init.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dso.h" +#include "policy.h" +#include "selinux_internal.h" +#include "setrans_internal.h" + +char *selinux_mnt = NULL; +int selinux_page_size = 0; + +int has_selinux_config = 0; + +/* Verify the mount point for selinux file system has a selinuxfs. + If the file system: + * Exist, + * Is mounted with an selinux file system, + * The file system is read/write + * then set this as the default file system. +*/ +static int verify_selinuxmnt(const char *mnt) +{ + struct statfs sfbuf; + int rc; + + do { + rc = statfs(mnt, &sfbuf); + } while (rc < 0 && errno == EINTR); + if (rc == 0) { + if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) { + struct statvfs vfsbuf; + rc = statvfs(mnt, &vfsbuf); + if (rc == 0) { + if (!(vfsbuf.f_flag & ST_RDONLY)) { + set_selinuxmnt(mnt); + } + return 0; + } + } + } + + return -1; +} + +int selinuxfs_exists(void) +{ + int exists = 0; + FILE *fp = NULL; + char *buf = NULL; + size_t len; + ssize_t num; + + fp = fopen("/proc/filesystems", "re"); + if (!fp) + return 1; /* Fail as if it exists */ + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + num = getline(&buf, &len, fp); + while (num != -1) { + if (strstr(buf, SELINUXFS)) { + exists = 1; + break; + } + num = getline(&buf, &len, fp); + } + + free(buf); + fclose(fp); + return exists; +} +hidden_def(selinuxfs_exists) + +static void init_selinuxmnt(void) +{ + char *buf=NULL, *p; + FILE *fp=NULL; + size_t len; + ssize_t num; + + if (selinux_mnt) + return; + + if (verify_selinuxmnt(SELINUXMNT) == 0) return; + + if (verify_selinuxmnt(OLDSELINUXMNT) == 0) return; + + /* Drop back to detecting it the long way. */ + if (!selinuxfs_exists()) + goto out; + + /* At this point, the usual spot doesn't have an selinuxfs so + * we look around for it */ + fp = fopen("/proc/mounts", "re"); + if (!fp) + goto out; + + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while ((num = getline(&buf, &len, fp)) != -1) { + char *tmp; + p = strchr(buf, ' '); + if (!p) + goto out; + p++; + tmp = strchr(p, ' '); + if (!tmp) + goto out; + if (!strncmp(tmp + 1, SELINUXFS" ", strlen(SELINUXFS)+1)) { + *tmp = '\0'; + break; + } + } + + /* If we found something, dup it */ + if (num > 0) + verify_selinuxmnt(p); + + out: + free(buf); + if (fp) + fclose(fp); + return; +} + +void fini_selinuxmnt(void) +{ + free(selinux_mnt); + selinux_mnt = NULL; +} + +hidden_def(fini_selinuxmnt) + +void set_selinuxmnt(const char *mnt) +{ + selinux_mnt = strdup(mnt); +} + +hidden_def(set_selinuxmnt) + +static void init_lib(void) __attribute__ ((constructor)); +static void init_lib(void) +{ + selinux_page_size = sysconf(_SC_PAGE_SIZE); + init_selinuxmnt(); +#ifndef ANDROID + has_selinux_config = (access(SELINUXCONFIG, F_OK) == 0); +#endif +} + +static void fini_lib(void) __attribute__ ((destructor)); +static void fini_lib(void) +{ + fini_selinuxmnt(); +} diff --git a/src/is_customizable_type.c b/src/is_customizable_type.c new file mode 100644 index 0000000..92876f4 --- /dev/null +++ b/src/is_customizable_type.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "context_internal.h" + +static int get_customizable_type_list(char *** retlist) +{ + FILE *fp; + char *buf; + unsigned int ctr = 0, i; + char **list = NULL; + + fp = fopen(selinux_customizable_types_path(), "re"); + if (!fp) + return -1; + + buf = malloc(selinux_page_size); + if (!buf) { + fclose(fp); + return -1; + } + while (fgets_unlocked(buf, selinux_page_size, fp) && ctr < UINT_MAX) { + ctr++; + } + rewind(fp); + if (ctr) { + list = + (char **) calloc(sizeof(char *), + ctr + 1); + if (list) { + i = 0; + while (fgets_unlocked(buf, selinux_page_size, fp) + && i < ctr) { + buf[strlen(buf) - 1] = 0; + list[i] = (char *) strdup(buf); + if (!list[i]) { + unsigned int j; + for (j = 0; j < i; j++) + free(list[j]); + free(list); + list = NULL; + break; + } + i++; + } + } + } + fclose(fp); + free(buf); + if (!list) + return -1; + *retlist = list; + return 0; +} + +static char **customizable_list = NULL; + +int is_context_customizable(const char * scontext) +{ + int i; + const char *type; + context_t c; + + if (!customizable_list) { + if (get_customizable_type_list(&customizable_list) != 0) + return -1; + } + + c = context_new(scontext); + if (!c) + return -1; + + type = context_type_get(c); + if (!type) { + context_free(c); + return -1; + } + + for (i = 0; customizable_list[i]; i++) { + if (strcmp(customizable_list[i], type) == 0) { + context_free(c); + return 1; + } + } + context_free(c); + return 0; +} diff --git a/src/label.c b/src/label.c new file mode 100644 index 0000000..8d586bd --- /dev/null +++ b/src/label.c @@ -0,0 +1,350 @@ +/* + * Generalized labeling frontend for userspace object managers. + * + * Author : Eamon Walsh + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#ifdef NO_MEDIA_BACKEND +#define CONFIG_MEDIA_BACKEND(fnptr) NULL +#else +#define CONFIG_MEDIA_BACKEND(fnptr) &fnptr +#endif + +#ifdef NO_X_BACKEND +#define CONFIG_X_BACKEND(fnptr) NULL +#else +#define CONFIG_X_BACKEND(fnptr) &fnptr +#endif + +#ifdef NO_DB_BACKEND +#define CONFIG_DB_BACKEND(fnptr) NULL +#else +#define CONFIG_DB_BACKEND(fnptr) &fnptr +#endif + +#ifdef NO_ANDROID_BACKEND +#define CONFIG_ANDROID_BACKEND(fnptr) NULL +#else +#define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr)) +#endif + +typedef int (*selabel_initfunc)(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts); + +static selabel_initfunc initfuncs[] = { + &selabel_file_init, + CONFIG_MEDIA_BACKEND(selabel_media_init), + CONFIG_X_BACKEND(selabel_x_init), + CONFIG_DB_BACKEND(selabel_db_init), + CONFIG_ANDROID_BACKEND(selabel_property_init), + CONFIG_ANDROID_BACKEND(selabel_service_init), +}; + +static inline struct selabel_digest *selabel_is_digest_set + (const struct selinux_opt *opts, + unsigned n, + struct selabel_digest *entry) +{ + struct selabel_digest *digest = NULL; + + while (n--) { + if (opts[n].type == SELABEL_OPT_DIGEST && + opts[n].value == (char *)1) { + digest = calloc(1, sizeof(*digest)); + if (!digest) + goto err; + + digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1); + if (!digest->digest) + goto err; + + digest->specfile_list = calloc(DIGEST_FILES_MAX, + sizeof(char *)); + if (!digest->specfile_list) + goto err; + + entry = digest; + return entry; + } + } + return NULL; + +err: + if (digest) { + free(digest->digest); + free(digest->specfile_list); + free(digest); + } + return NULL; +} + +static void selabel_digest_fini(struct selabel_digest *ptr) +{ + int i; + + free(ptr->digest); + free(ptr->hashbuf); + + if (ptr->specfile_list) { + for (i = 0; ptr->specfile_list[i]; i++) + free(ptr->specfile_list[i]); + free(ptr->specfile_list); + } + free(ptr); +} + +/* + * Validation functions + */ + +static inline int selabel_is_validate_set(const struct selinux_opt *opts, + unsigned n) +{ + while (n--) + if (opts[n].type == SELABEL_OPT_VALIDATE) + return !!opts[n].value; + + return 0; +} + +int selabel_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts) +{ + int rc = 0; + + if (!rec->validating || contexts->validated) + goto out; + + rc = selinux_validate(&contexts->ctx_raw); + if (rc < 0) + goto out; + + contexts->validated = 1; +out: + return rc; +} + +/* Public API helpers */ +static int selabel_fini(struct selabel_handle *rec, + struct selabel_lookup_rec *lr, + int translating) +{ + if (compat_validate(rec, lr, rec->spec_file, lr->lineno)) + return -1; + + if (translating && !lr->ctx_trans && + selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) + return -1; + + return 0; +} + +static struct selabel_lookup_rec * +selabel_lookup_common(struct selabel_handle *rec, int translating, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + + if (key == NULL) { + errno = EINVAL; + return NULL; + } + + lr = rec->func_lookup(rec, key, type); + if (!lr) + return NULL; + + if (selabel_fini(rec, lr, translating)) + return NULL; + + return lr; +} + +static struct selabel_lookup_rec * +selabel_lookup_bm_common(struct selabel_handle *rec, int translating, + const char *key, int type, const char **aliases) +{ + struct selabel_lookup_rec *lr; + + if (key == NULL) { + errno = EINVAL; + return NULL; + } + + lr = rec->func_lookup_best_match(rec, key, aliases, type); + if (!lr) + return NULL; + + if (selabel_fini(rec, lr, translating)) + return NULL; + + return lr; +} + +/* + * Public API + */ + +struct selabel_handle *selabel_open(unsigned int backend, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct selabel_handle *rec = NULL; + + if (backend >= ARRAY_SIZE(initfuncs)) { + errno = EINVAL; + goto out; + } + + if (!initfuncs[backend]) { + errno = ENOTSUP; + goto out; + } + + rec = (struct selabel_handle *)malloc(sizeof(*rec)); + if (!rec) + goto out; + + memset(rec, 0, sizeof(*rec)); + rec->backend = backend; + rec->validating = selabel_is_validate_set(opts, nopts); + + rec->digest = selabel_is_digest_set(opts, nopts, rec->digest); + + if ((*initfuncs[backend])(rec, opts, nopts)) { + free(rec->spec_file); + free(rec); + rec = NULL; + } + +out: + return rec; +} + +int selabel_lookup(struct selabel_handle *rec, char **con, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + + lr = selabel_lookup_common(rec, 1, key, type); + if (!lr) + return -1; + + *con = strdup(lr->ctx_trans); + return *con ? 0 : -1; +} + +int selabel_lookup_raw(struct selabel_handle *rec, char **con, + const char *key, int type) +{ + struct selabel_lookup_rec *lr; + + lr = selabel_lookup_common(rec, 0, key, type); + if (!lr) + return -1; + + *con = strdup(lr->ctx_raw); + return *con ? 0 : -1; +} + +bool selabel_partial_match(struct selabel_handle *rec, const char *key) +{ + if (!rec->func_partial_match) { + /* + * If the label backend does not support partial matching, + * then assume a match is possible. + */ + return true; + } + + return rec->func_partial_match(rec, key); +} + +int selabel_lookup_best_match(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type) +{ + struct selabel_lookup_rec *lr; + + if (!rec->func_lookup_best_match) { + errno = ENOTSUP; + return -1; + } + + lr = selabel_lookup_bm_common(rec, 1, key, type, aliases); + if (!lr) + return -1; + + *con = strdup(lr->ctx_trans); + return *con ? 0 : -1; +} + +int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type) +{ + struct selabel_lookup_rec *lr; + + if (!rec->func_lookup_best_match) { + errno = ENOTSUP; + return -1; + } + + lr = selabel_lookup_bm_common(rec, 0, key, type, aliases); + if (!lr) + return -1; + + *con = strdup(lr->ctx_raw); + return *con ? 0 : -1; +} + +enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, + struct selabel_handle *h2) +{ + if (!h1->func_cmp || h1->func_cmp != h2->func_cmp) + return SELABEL_INCOMPARABLE; + + return h1->func_cmp(h1, h2); +} + +int selabel_digest(struct selabel_handle *rec, + unsigned char **digest, size_t *digest_len, + char ***specfiles, size_t *num_specfiles) +{ + if (!rec->digest) { + errno = EINVAL; + return -1; + } + + *digest = rec->digest->digest; + *digest_len = DIGEST_SPECFILE_SIZE; + *specfiles = rec->digest->specfile_list; + *num_specfiles = rec->digest->specfile_cnt; + return 0; +} + +void selabel_close(struct selabel_handle *rec) +{ + if (rec->digest) + selabel_digest_fini(rec->digest); + rec->func_close(rec); + free(rec->spec_file); + free(rec); +} + +void selabel_stats(struct selabel_handle *rec) +{ + rec->func_stats(rec); +} diff --git a/src/label_backends_android.c b/src/label_backends_android.c new file mode 100644 index 0000000..cb8aae2 --- /dev/null +++ b/src/label_backends_android.c @@ -0,0 +1,351 @@ +/* + * Property Service contexts backend for labeling Android + * property keys + */ + +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +/* A property security context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *property_key; /* property key string */ +} spec_t; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications is sorted for longest + * prefix match + */ + spec_t *spec_arr; + unsigned int nspec; /* total number of specifications */ +}; + +static int cmp(const void *A, const void *B) +{ + const struct spec *sp1 = A, *sp2 = B; + + if (strncmp(sp1->property_key, "*", 1) == 0) + return 1; + if (strncmp(sp2->property_key, "*", 1) == 0) + return -1; + + size_t L1 = strlen(sp1->property_key); + size_t L2 = strlen(sp2->property_key); + + return (L1 < L2) - (L1 > L2); +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if (!strcmp(spec_arr[jj].property_key, + curr_spec->property_key)) { + rc = -1; + errno = EINVAL; + if (strcmp(spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + selinux_log + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->property_key, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + selinux_log + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->property_key); + } + } + } + } + return rc; +} + +static int process_line(struct selabel_handle *rec, + const char *path, char *line_buf, + int pass, unsigned lineno) +{ + int items; + char *prop = NULL, *context = NULL; + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int nspec = data->nspec; + const char *errbuf = NULL; + + items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); + if (items < 0) { + items = errno; + selinux_log(SELINUX_ERROR, + "%s: line %u error due to: %s\n", path, + lineno, errbuf ?: strerror(errno)); + errno = items; + return -1; + } + + if (items == 0) + return items; + + if (items != 2) { + selinux_log(SELINUX_ERROR, + "%s: line %u is missing fields\n", path, + lineno); + free(prop); + errno = EINVAL; + return -1; + } + + if (pass == 0) { + free(prop); + free(context); + } else if (pass == 1) { + /* On the second pass, process and store the specification in spec. */ + spec_arr[nspec].property_key = prop; + spec_arr[nspec].lr.ctx_raw = context; + + if (rec->validating) { + if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { + selinux_log(SELINUX_ERROR, + "%s: line %u has invalid context %s\n", + path, lineno, spec_arr[nspec].lr.ctx_raw); + errno = EINVAL; + return -1; + } + } + } + + data->nspec = ++nspec; + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + FILE *fp; + char line_buf[BUFSIZ]; + unsigned int lineno, maxnspec, pass; + int status = -1; + struct stat sb; + + /* Process arguments */ + while (n--) + switch (opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + if (!path) + return -1; + + /* Open the specification file. */ + if ((fp = fopen(path, "re")) == NULL) + return -1; + + if (fstat(fileno(fp), &sb) < 0) + goto finish; + errno = EINVAL; + if (!S_ISREG(sb.st_mode)) + goto finish; + + /* + * Two passes of the specification file. First is to get the size. + * After the first pass, the spec array is malloced to the appropriate + * size. Second pass is to populate the spec array and check for + * dups. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + data->nspec = 0; + lineno = 0; + + while (fgets(line_buf, sizeof(line_buf) - 1, fp) + && data->nspec < maxnspec) { + if (process_line(rec, path, line_buf, pass, ++lineno) + != 0) + goto finish; + } + + if (pass == 1) { + status = nodups_specs(data, path); + + if (status) + goto finish; + } + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + + if (NULL == (data->spec_arr = + calloc(data->nspec, sizeof(spec_t)))) + goto finish; + + maxnspec = data->nspec; + rewind(fp); + } + } + + qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->property_key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (data->spec_arr) + free(data->spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *property_lookup(struct selabel_handle *rec, + const char *key, + int __attribute__((unused)) type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + struct selabel_lookup_rec *ret = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + for (i = 0; i < data->nspec; i++) { + if (strncmp(spec_arr[i].property_key, key, + strlen(spec_arr[i].property_key)) == 0) { + break; + } + if (strncmp(spec_arr[i].property_key, "*", 1) == 0) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + ret = &spec_arr[i].lr; + +finish: + return ret; +} + +static struct selabel_lookup_rec *service_lookup(struct selabel_handle *rec, + const char *key, int __attribute__((unused)) type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + struct selabel_lookup_rec *ret = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + for (i = 0; i < data->nspec; i++) { + if (strcmp(spec_arr[i].property_key, key) == 0) + break; + if (strcmp(spec_arr[i].property_key, "*") == 0) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + ret = &spec_arr[i].lr; + +finish: + return ret; +} + +static void stats(struct selabel_handle __attribute__((unused)) *rec) +{ + selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); +} + +int selabel_property_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)calloc(1, sizeof(*data)); + if (!data) + return -1; + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &property_lookup; + + return init(rec, opts, nopts); +} + +int selabel_service_init(struct selabel_handle *rec, + const struct selinux_opt *opts, unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)calloc(1, sizeof(*data)); + if (!data) + return -1; + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &service_lookup; + + return init(rec, opts, nopts); +} diff --git a/src/label_db.c b/src/label_db.c new file mode 100644 index 0000000..fba96c9 --- /dev/null +++ b/src/label_db.c @@ -0,0 +1,362 @@ +/* + * Media contexts backend for DB objects + * + * Author: KaiGai Kohei + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +/* + * Regular database object's security context interface + * + * It provides applications a regular security context for the given + * database objects. The pair of object's name and a security context + * are described in the specfile. In the default, it shall be stored + * in the /etc/selinux/$POLICYTYPE/contexts/sepgsql_contexts . + * (It assumes SE-PostgreSQL in the default. For other RDBMS, use the + * SELABEL_OPT_PATH option to specify different specfile.) + * + * Each line has the following format: + * + * + * For example: + * ---------------------------------------- + * # + * # It is an example specfile for database obejcts + * # + * db_database template1 system_u:object_r:sepgsql_db_t:s0 + * + * db_schema *.pg_catalog system_u:object_r:sepgsql_sys_schema_t:s0 + * + * db_table *.pg_catalog.* system_u:object_r:sepgsql_sysobj_t:s0 + * db_column *.pg_catalog.*.* system_u:object_r:sepgsql_sysobj_t:s0 + * ---------------------------------------- + * + * All the characters after the '#' are dealt as comments. + * + * The first token is object class. SELABEL_DB_* declared in label.h are + * corresponding to a certain database object. + * + * The object name/identifier is compared to the given key. + * A database object can have its own namespace hierarchy. + * In the case of SE-PgSQL, database is the top level object, and schema + * is deployed just under a database. A schema can contains various kind + * of objects, such as tables, procedures and so on. + * Thus, when we lookup an expected security context for a table of + * "pg_class", it is necessary to assume selabel_lookup() is called with + * "postgres.pg_catalog.pg_class", not just a "pg_class". + * + * Wildcards ('*' or '?') are available on the patterns, so if you want + * to match a table within any schema, you should set '*' on the upper + * namespaces of the table. + * + * The structure of namespace depends on RDBMS. + * For example, Trusted-RUBIX has an idea of "catalog" which performs + * as a namespace between a database and individual schemas. In this + * case, a table has upper three layers. + */ + +/* + * spec_t : It holds a pair of a key and an expected security context + */ +typedef struct spec { + struct selabel_lookup_rec lr; + char *key; + int type; + int matches; +} spec_t; + +/* + * catalog_t : An array of spec_t + */ +typedef struct catalog { + unsigned int nspec; /* number of specs in use */ + unsigned int limit; /* physical limitation of specs[] */ + spec_t specs[0]; +} catalog_t; + +/* + * Helper function to parse a line read from the specfile + */ +static int +process_line(const char *path, char *line_buf, unsigned int line_num, + catalog_t *catalog) +{ + spec_t *spec = &catalog->specs[catalog->nspec]; + char *type, *key, *context, *temp; + int items; + + /* Cut off comments */ + temp = strchr(line_buf, '#'); + if (temp) + *temp = '\0'; + + /* + * Every entry must have the following format + * + */ + type = key = context = temp = NULL; + items = sscanf(line_buf, "%ms %ms %ms %ms", + &type, &key, &context, &temp); + if (items != 3) { + if (items > 0) + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid format, skipped", + path, line_num); + goto skip; + } + + /* + * Set up individual spec entry + */ + memset(spec, 0, sizeof(spec_t)); + + if (!strcmp(type, "db_database")) + spec->type = SELABEL_DB_DATABASE; + else if (!strcmp(type, "db_schema")) + spec->type = SELABEL_DB_SCHEMA; + else if (!strcmp(type, "db_table")) + spec->type = SELABEL_DB_TABLE; + else if (!strcmp(type, "db_column")) + spec->type = SELABEL_DB_COLUMN; + else if (!strcmp(type, "db_sequence")) + spec->type = SELABEL_DB_SEQUENCE; + else if (!strcmp(type, "db_view")) + spec->type = SELABEL_DB_VIEW; + else if (!strcmp(type, "db_procedure")) + spec->type = SELABEL_DB_PROCEDURE; + else if (!strcmp(type, "db_blob")) + spec->type = SELABEL_DB_BLOB; + else if (!strcmp(type, "db_tuple")) + spec->type = SELABEL_DB_TUPLE; + else if (!strcmp(type, "db_language")) + spec->type = SELABEL_DB_LANGUAGE; + else if (!strcmp(type, "db_exception")) + spec->type = SELABEL_DB_EXCEPTION; + else if (!strcmp(type, "db_datatype")) + spec->type = SELABEL_DB_DATATYPE; + else { + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid object type %s\n", + path, line_num, type); + goto skip; + } + + free(type); + spec->key = key; + spec->lr.ctx_raw = context; + + catalog->nspec++; + + return 0; + +skip: + free(type); + free(key); + free(context); + free(temp); + + return 0; +} + +/* + * selabel_close() handler + */ +static void +db_close(struct selabel_handle *rec) +{ + catalog_t *catalog = (catalog_t *)rec->data; + spec_t *spec; + unsigned int i; + + for (i = 0; i < catalog->nspec; i++) { + spec = &catalog->specs[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + free(catalog); +} + +/* + * selabel_lookup() handler + */ +static struct selabel_lookup_rec * +db_lookup(struct selabel_handle *rec, const char *key, int type) +{ + catalog_t *catalog = (catalog_t *)rec->data; + spec_t *spec; + unsigned int i; + + for (i = 0; i < catalog->nspec; i++) { + spec = &catalog->specs[i]; + + if (spec->type != type) + continue; + if (!fnmatch(spec->key, key, 0)) { + spec->matches++; + + return &spec->lr; + } + } + + /* No found */ + errno = ENOENT; + return NULL; +} + +/* + * selabel_stats() handler + */ +static void +db_stats(struct selabel_handle *rec) +{ + catalog_t *catalog = (catalog_t *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < catalog->nspec; i++) + total += catalog->specs[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + catalog->nspec, total); +} + +/* + * selabel_open() handler + */ +static catalog_t * +db_init(const struct selinux_opt *opts, unsigned nopts, + struct selabel_handle *rec) +{ + catalog_t *catalog; + FILE *filp; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + unsigned int line_num = 0; + unsigned int i; + struct stat sb; + + /* + * Initialize catalog data structure + */ + catalog = malloc(sizeof(catalog_t) + 32 * sizeof(spec_t)); + if (!catalog) + return NULL; + catalog->limit = 32; + catalog->nspec = 0; + + /* + * Process arguments + * + * SELABEL_OPT_PATH: + * It allows to specify an alternative specification file instead of + * the default one. If RDBMS is not SE-PostgreSQL, it may need to + * specify an explicit specfile for database objects. + */ + while (nopts--) { + switch (opts[nopts].type) { + case SELABEL_OPT_PATH: + path = opts[nopts].value; + break; + } + } + + /* + * Open the specification file + */ + if (!path) + path = selinux_sepgsql_context_path(); + + if ((filp = fopen(path, "rb")) == NULL) { + free(catalog); + return NULL; + } + if (fstat(fileno(filp), &sb) < 0) { + free(catalog); + fclose(filp); + return NULL; + } + if (!S_ISREG(sb.st_mode)) { + free(catalog); + fclose(filp); + errno = EINVAL; + return NULL; + } + rec->spec_file = strdup(path); + + /* + * Parse for each lines + */ + while (getline(&line_buf, &line_len, filp) > 0) { + /* + * Expand catalog array, if necessary + */ + if (catalog->limit == catalog->nspec) { + size_t length; + unsigned int new_limit = 2 * catalog->limit; + catalog_t *new_catalog; + + length = sizeof(catalog_t) + + new_limit * sizeof(spec_t); + new_catalog = realloc(catalog, length); + if (!new_catalog) + goto out_error; + + catalog = new_catalog; + catalog->limit = new_limit; + } + + /* + * Parse a line + */ + if (process_line(path, line_buf, ++line_num, catalog) < 0) + goto out_error; + } + free(line_buf); + + if (digest_add_specfile(rec->digest, filp, NULL, sb.st_size, path) < 0) + goto out_error; + + digest_gen_hash(rec->digest); + + fclose(filp); + + return catalog; + +out_error: + for (i = 0; i < catalog->nspec; i++) { + spec_t *spec = &catalog->specs[i]; + + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + free(catalog); + fclose(filp); + + return NULL; +} + +/* + * Initialize selabel_handle and load the entries of specfile + */ +int selabel_db_init(struct selabel_handle *rec, + const struct selinux_opt *opts, unsigned nopts) +{ + rec->func_close = &db_close; + rec->func_lookup = &db_lookup; + rec->func_stats = &db_stats; + rec->data = db_init(opts, nopts, rec); + + return !rec->data ? -1 : 0; +} diff --git a/src/label_file.c b/src/label_file.c new file mode 100644 index 0000000..b81fd55 --- /dev/null +++ b/src/label_file.c @@ -0,0 +1,1140 @@ +/* + * File contexts backend for labeling system + * + * Author : Eamon Walsh + * Author : Stephen Smalley + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "callbacks.h" +#include "label_internal.h" +#include "label_file.h" + +/* + * Internals, mostly moved over from matchpathcon.c + */ + +/* return the length of the text that is the stem of a file name */ +static int get_stem_from_file_name(const char *const buf) +{ + const char *tmp = strchr(buf + 1, '/'); + + if (!tmp) + return 0; + return tmp - buf; +} + +/* find the stem of a file name, returns the index into stem_arr (or -1 if + * there is no match - IE for a file in the root directory or a regex that is + * too complex for us). Makes buf point to the text AFTER the stem. */ +static int find_stem_from_file(struct saved_data *data, const char **buf) +{ + int i; + int stem_len = get_stem_from_file_name(*buf); + + if (!stem_len) + return -1; + for (i = 0; i < data->num_stems; i++) { + if (stem_len == data->stem_arr[i].len + && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) { + *buf += stem_len; + return i; + } + } + return -1; +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if ((!strcmp(spec_arr[jj].regex_str, + curr_spec->regex_str)) + && (!spec_arr[jj].mode || !curr_spec->mode + || spec_arr[jj].mode == curr_spec->mode)) { + rc = -1; + errno = EINVAL; + if (strcmp(spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + COMPAT_LOG + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->regex_str, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + COMPAT_LOG + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->regex_str); + } + } + } + } + return rc; +} + +static int process_text_file(FILE *fp, const char *prefix, + struct selabel_handle *rec, const char *path) +{ + int rc; + size_t line_len; + unsigned int lineno = 0; + char *line_buf = NULL; + + while (getline(&line_buf, &line_len, fp) > 0) { + rc = process_line(rec, path, prefix, line_buf, ++lineno); + if (rc) + goto out; + } + rc = 0; +out: + free(line_buf); + return rc; +} + +static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec, + const char *path) +{ + struct saved_data *data = (struct saved_data *)rec->data; + int rc; + char *addr, *str_buf; + int *stem_map; + struct mmap_area *mmap_area; + uint32_t i, magic, version; + uint32_t entry_len, stem_map_len, regex_array_len; + const char *reg_version; + const char *reg_arch; + char reg_arch_matches = 0; + + mmap_area = malloc(sizeof(*mmap_area)); + if (!mmap_area) { + return -1; + } + + addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); + if (addr == MAP_FAILED) { + free(mmap_area); + perror("mmap"); + return -1; + } + + /* save where we mmap'd the file to cleanup on close() */ + mmap_area->addr = mmap_area->next_addr = addr; + mmap_area->len = mmap_area->next_len = len; + mmap_area->next = data->mmap_areas; + data->mmap_areas = mmap_area; + + /* check if this looks like an fcontext file */ + rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); + if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) + return -1; + + /* check if this version is higher than we understand */ + rc = next_entry(&version, mmap_area, sizeof(uint32_t)); + if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) + return -1; + + reg_version = regex_version(); + if (!reg_version) + return -1; + + reg_arch = regex_arch_string(); + if (!reg_arch) + return -1; + + if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { + + len = strlen(reg_version); + + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0) + return -1; + + /* Check version lengths */ + if (len != entry_len) + return -1; + + /* Check if regex version mismatch */ + str_buf = malloc(entry_len + 1); + if (!str_buf) + return -1; + + rc = next_entry(str_buf, mmap_area, entry_len); + if (rc < 0) { + free(str_buf); + return -1; + } + + str_buf[entry_len] = '\0'; + if ((strcmp(str_buf, reg_version) != 0)) { + free(str_buf); + return -1; + } + free(str_buf); + + if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) { + len = strlen(reg_arch); + + rc = next_entry(&entry_len, mmap_area, + sizeof(uint32_t)); + if (rc < 0) + return -1; + + /* Check arch string lengths */ + if (len != entry_len) { + /* + * Skip the entry and conclude that we have + * a mismatch, which is not fatal. + */ + next_entry(NULL, mmap_area, entry_len); + goto end_arch_check; + } + + /* Check if arch string mismatch */ + str_buf = malloc(entry_len + 1); + if (!str_buf) + return -1; + + rc = next_entry(str_buf, mmap_area, entry_len); + if (rc < 0) { + free(str_buf); + return -1; + } + + str_buf[entry_len] = '\0'; + reg_arch_matches = strcmp(str_buf, reg_arch) == 0; + free(str_buf); + } + } +end_arch_check: + + /* allocate the stems_data array */ + rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); + if (rc < 0) + return -1; + + /* + * map indexed by the stem # in the mmap file and contains the stem + * number in the data stem_arr + */ + stem_map = calloc(stem_map_len, sizeof(*stem_map)); + if (!stem_map) + return -1; + + for (i = 0; i < stem_map_len; i++) { + char *buf; + uint32_t stem_len; + int newid; + + /* the length does not inlude the nul */ + rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !stem_len) { + rc = -1; + goto out; + } + + /* Check for stem_len wrap around. */ + if (stem_len < UINT32_MAX) { + buf = (char *)mmap_area->next_addr; + /* Check if over-run before null check. */ + rc = next_entry(NULL, mmap_area, (stem_len + 1)); + if (rc < 0) + goto out; + + if (buf[stem_len] != '\0') { + rc = -1; + goto out; + } + } else { + rc = -1; + goto out; + } + + /* store the mapping between old and new */ + newid = find_stem(data, buf, stem_len); + if (newid < 0) { + newid = store_stem(data, buf, stem_len); + if (newid < 0) { + rc = newid; + goto out; + } + data->stem_arr[newid].from_mmap = 1; + } + stem_map[i] = newid; + } + + /* allocate the regex array */ + rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !regex_array_len) { + rc = -1; + goto out; + } + + for (i = 0; i < regex_array_len; i++) { + struct spec *spec; + int32_t stem_id, meta_chars; + uint32_t mode = 0, prefix_len = 0; + + rc = grow_specs(data); + if (rc < 0) + goto out; + + spec = &data->spec_arr[data->nspec]; + spec->from_mmap = 1; + + /* Process context */ + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto out; + } + + str_buf = malloc(entry_len); + if (!str_buf) { + rc = -1; + goto out; + } + rc = next_entry(str_buf, mmap_area, entry_len); + if (rc < 0) { + free(str_buf); + goto out; + } + + if (str_buf[entry_len - 1] != '\0') { + free(str_buf); + rc = -1; + goto out; + } + spec->lr.ctx_raw = str_buf; + + if (strcmp(spec->lr.ctx_raw, "<>") && rec->validating) { + if (selabel_validate(rec, &spec->lr) < 0) { + selinux_log(SELINUX_ERROR, + "%s: context %s is invalid\n", + path, spec->lr.ctx_raw); + goto out; + } + } + + /* Process regex string */ + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) { + rc = -1; + goto out; + } + + spec->regex_str = (char *)mmap_area->next_addr; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto out; + + if (spec->regex_str[entry_len - 1] != '\0') { + rc = -1; + goto out; + } + + /* Process mode */ + if (version >= SELINUX_COMPILED_FCONTEXT_MODE) + rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); + else + rc = next_entry(&mode, mmap_area, sizeof(mode_t)); + if (rc < 0) + goto out; + + spec->mode = mode; + + /* map the stem id from the mmap file to the data->stem_arr */ + rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); + if (rc < 0) + goto out; + + if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) + spec->stem_id = -1; + else + spec->stem_id = stem_map[stem_id]; + + /* retrieve the hasMetaChars bit */ + rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); + if (rc < 0) + goto out; + + spec->hasMetaChars = meta_chars; + /* and prefix length for use by selabel_lookup_best_match */ + if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { + rc = next_entry(&prefix_len, mmap_area, + sizeof(uint32_t)); + if (rc < 0) + goto out; + + spec->prefix_len = prefix_len; + } + + rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches, + &spec->regex_compiled); + if (rc < 0) + goto out; + + __pthread_mutex_init(&spec->regex_lock, NULL); + data->nspec++; + } + + rc = 0; +out: + free(stem_map); + + return rc; +} + +struct file_details { + const char *suffix; + struct stat sb; +}; + +static char *rolling_append(char *current, const char *suffix, size_t max) +{ + size_t size; + size_t suffix_size; + size_t current_size; + + if (!suffix) + return current; + + current_size = strlen(current); + suffix_size = strlen(suffix); + + size = current_size + suffix_size; + if (size < current_size || size < suffix_size) + return NULL; + + /* ensure space for the '.' and the '\0' characters. */ + if (size >= (SIZE_MAX - 2)) + return NULL; + + size += 2; + + if (size > max) + return NULL; + + /* Append any given suffix */ + char *to = current + current_size; + *to++ = '.'; + strcpy(to, suffix); + + return current; +} + +static bool fcontext_is_binary(FILE *fp) +{ + uint32_t magic; + + size_t len = fread(&magic, sizeof(magic), 1, fp); + rewind(fp); + + return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT)); +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static FILE *open_file(const char *path, const char *suffix, + char *save_path, size_t len, struct stat *sb, bool open_oldest) +{ + unsigned int i; + int rc; + char stack_path[len]; + struct file_details *found = NULL; + + /* + * Rolling append of suffix. Try to open with path.suffix then the + * next as path.suffix.suffix and so forth. + */ + struct file_details fdetails[2] = { + { .suffix = suffix }, + { .suffix = "bin" } + }; + + rc = snprintf(stack_path, sizeof(stack_path), "%s", path); + if (rc >= (int) sizeof(stack_path)) { + errno = ENAMETOOLONG; + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(fdetails); i++) { + + /* This handles the case if suffix is null */ + path = rolling_append(stack_path, fdetails[i].suffix, + sizeof(stack_path)); + if (!path) + return NULL; + + rc = stat(path, &fdetails[i].sb); + if (rc) + continue; + + /* first file thing found, just take it */ + if (!found) { + strcpy(save_path, path); + found = &fdetails[i]; + continue; + } + + /* + * Keep picking the newest file found. Where "newest" + * includes equality. This provides a precedence on + * secondary suffixes even when the timestamp is the + * same. Ie choose file_contexts.bin over file_contexts + * even if the time stamp is the same. Invert this logic + * on open_oldest set to true. The idea is that if the + * newest file failed to process, we can attempt to + * process the oldest. The logic here is subtle and depends + * on the array ordering in fdetails for the case when time + * stamps are the same. + */ + if (open_oldest ^ + (fdetails[i].sb.st_mtime >= found->sb.st_mtime)) { + found = &fdetails[i]; + strcpy(save_path, path); + } + } + + if (!found) { + errno = ENOENT; + return NULL; + } + + memcpy(sb, &found->sb, sizeof(*sb)); + return fopen(save_path, "re"); +} + +static int process_file(const char *path, const char *suffix, + struct selabel_handle *rec, + const char *prefix, struct selabel_digest *digest) +{ + int rc; + unsigned int i; + struct stat sb; + FILE *fp = NULL; + char found_path[PATH_MAX]; + + /* + * On the first pass open the newest modified file. If it fails to + * process, then the second pass shall open the oldest file. If both + * passes fail, then it's a fatal error. + */ + for (i = 0; i < 2; i++) { + fp = open_file(path, suffix, found_path, sizeof(found_path), + &sb, i > 0); + if (fp == NULL) + return -1; + + rc = fcontext_is_binary(fp) ? + load_mmap(fp, sb.st_size, rec, found_path) : + process_text_file(fp, prefix, rec, found_path); + if (!rc) + rc = digest_add_specfile(digest, fp, NULL, sb.st_size, + found_path); + + fclose(fp); + + if (!rc) + return 0; + } + return -1; +} + +static void selabel_subs_fini(struct selabel_sub *ptr) +{ + struct selabel_sub *next; + + while (ptr) { + next = ptr->next; + free(ptr->src); + free(ptr->dst); + free(ptr); + ptr = next; + } +} + +static char *selabel_sub(struct selabel_sub *ptr, const char *src) +{ + char *dst = NULL; + int len; + + while (ptr) { + if (strncmp(src, ptr->src, ptr->slen) == 0 ) { + if (src[ptr->slen] == '/' || + src[ptr->slen] == 0) { + if ((src[ptr->slen] == '/') && + (strcmp(ptr->dst, "/") == 0)) + len = ptr->slen + 1; + else + len = ptr->slen; + if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0) + return NULL; + return dst; + } + } + ptr = ptr->next; + } + return NULL; +} + +static int selabel_subs_init(const char *path, struct selabel_digest *digest, + struct selabel_sub **out_subs) +{ + char buf[1024]; + FILE *cfg = fopen(path, "re"); + struct selabel_sub *list = NULL, *sub = NULL; + struct stat sb; + int status = -1; + + *out_subs = NULL; + if (!cfg) { + /* If the file does not exist, it is not fatal */ + return (errno == ENOENT) ? 0 : -1; + } + + if (fstat(fileno(cfg), &sb) < 0) + goto out; + + while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { + char *ptr = NULL; + char *src = buf; + char *dst = NULL; + + while (*src && isspace(*src)) + src++; + if (src[0] == '#') continue; + ptr = src; + while (*ptr && ! isspace(*ptr)) + ptr++; + *ptr++ = '\0'; + if (! *src) continue; + + dst = ptr; + while (*dst && isspace(*dst)) + dst++; + ptr=dst; + while (*ptr && ! isspace(*ptr)) + ptr++; + *ptr='\0'; + if (! *dst) + continue; + + sub = malloc(sizeof(*sub)); + if (! sub) + goto err; + memset(sub, 0, sizeof(*sub)); + + sub->src=strdup(src); + if (! sub->src) + goto err; + + sub->dst=strdup(dst); + if (! sub->dst) + goto err; + + sub->slen = strlen(src); + sub->next = list; + list = sub; + sub = NULL; + } + + if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0) + goto err; + + *out_subs = list; + status = 0; + +out: + fclose(cfg); + return status; +err: + if (sub) + free(sub->src); + free(sub); + while (list) { + sub = list->next; + free(list->src); + free(list->dst); + free(list); + list = sub; + } + goto out; +} + +static char *selabel_sub_key(struct saved_data *data, const char *key) +{ + char *ptr = NULL; + char *dptr = NULL; + + ptr = selabel_sub(data->subs, key); + if (ptr) { + dptr = selabel_sub(data->dist_subs, ptr); + if (dptr) { + free(ptr); + ptr = dptr; + } + } else { + ptr = selabel_sub(data->dist_subs, key); + } + if (ptr) + return ptr; + + return NULL; +} + +static void closef(struct selabel_handle *rec); + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + const char *prefix = NULL; + int status = -1, baseonly = 0; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + case SELABEL_OPT_SUBSET: + prefix = opts[n].value; + break; + case SELABEL_OPT_BASEONLY: + baseonly = !!opts[n].value; + break; + } + +#if !defined(BUILD_HOST) && !defined(ANDROID) + char subs_file[PATH_MAX + 1]; + /* Process local and distribution substitution files */ + if (!path) { + status = selabel_subs_init( + selinux_file_context_subs_dist_path(), + rec->digest, &data->dist_subs); + if (status) + goto finish; + status = selabel_subs_init(selinux_file_context_subs_path(), + rec->digest, &data->subs); + if (status) + goto finish; + path = selinux_file_context_path(); + } else { + snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path); + status = selabel_subs_init(subs_file, rec->digest, + &data->dist_subs); + if (status) + goto finish; + snprintf(subs_file, sizeof(subs_file), "%s.subs", path); + status = selabel_subs_init(subs_file, rec->digest, + &data->subs); + if (status) + goto finish; + } + +#endif + rec->spec_file = strdup(path); + + /* + * The do detailed validation of the input and fill the spec array + */ + status = process_file(path, NULL, rec, prefix, rec->digest); + if (status) + goto finish; + + if (rec->validating) { + status = nodups_specs(data, path); + if (status) + goto finish; + } + + if (!baseonly) { + status = process_file(path, "homedirs", rec, prefix, + rec->digest); + if (status && errno != ENOENT) + goto finish; + + status = process_file(path, "local", rec, prefix, + rec->digest); + if (status && errno != ENOENT) + goto finish; + } + + digest_gen_hash(rec->digest); + + status = sort_specs(data); + +finish: + if (status) + closef(rec); + + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct mmap_area *area, *last_area; + struct spec *spec; + struct stem *stem; + unsigned int i; + + selabel_subs_fini(data->subs); + selabel_subs_fini(data->dist_subs); + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->lr.ctx_trans); + free(spec->lr.ctx_raw); + regex_data_free(spec->regex); + __pthread_mutex_destroy(&spec->regex_lock); + if (spec->from_mmap) + continue; + free(spec->regex_str); + free(spec->type_str); + } + + for (i = 0; i < (unsigned int)data->num_stems; i++) { + stem = &data->stem_arr[i]; + if (stem->from_mmap) + continue; + free(stem->buf); + } + + if (data->spec_arr) + free(data->spec_arr); + if (data->stem_arr) + free(data->stem_arr); + + area = data->mmap_areas; + while (area) { + munmap(area->addr, area->len); + last_area = area; + area = area->next; + free(last_area); + } + free(data); +} + +static struct spec *lookup_common(struct selabel_handle *rec, + const char *key, + int type, + bool partial) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec_arr = data->spec_arr; + int i, rc, file_stem; + mode_t mode = (mode_t)type; + const char *buf; + struct spec *ret = NULL; + char *clean_key = NULL; + const char *prev_slash, *next_slash; + unsigned int sofar = 0; + char *sub = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + /* Remove duplicate slashes */ + if ((next_slash = strstr(key, "//"))) { + clean_key = (char *) malloc(strlen(key) + 1); + if (!clean_key) + goto finish; + prev_slash = key; + while (next_slash) { + memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash); + sofar += next_slash - prev_slash; + prev_slash = next_slash + 1; + next_slash = strstr(prev_slash, "//"); + } + strcpy(clean_key + sofar, prev_slash); + key = clean_key; + } + + sub = selabel_sub_key(data, key); + if (sub) + key = sub; + + buf = key; + file_stem = find_stem_from_file(data, &buf); + mode &= S_IFMT; + + /* + * Check for matching specifications in reverse order, so that + * the last matching specification is used. + */ + for (i = data->nspec - 1; i >= 0; i--) { + struct spec *spec = &spec_arr[i]; + /* if the spec in question matches no stem or has the same + * stem as the file AND if the spec in question has no mode + * specified or if the mode matches the file mode then we do + * a regex check */ + if ((spec->stem_id == -1 || spec->stem_id == file_stem) && + (!mode || !spec->mode || mode == spec->mode)) { + if (compile_regex(data, spec, NULL) < 0) + goto finish; + if (spec->stem_id == -1) + rc = regex_match(spec->regex, key, partial); + else + rc = regex_match(spec->regex, buf, partial); + if (rc == REGEX_MATCH) { + spec->matches++; + break; + } else if (partial && rc == REGEX_MATCH_PARTIAL) + break; + + if (rc == REGEX_NO_MATCH) + continue; + + errno = ENOENT; + /* else it's an error */ + goto finish; + } + } + + if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<>") == 0) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + errno = 0; + ret = &spec_arr[i]; + +finish: + free(clean_key); + free(sub); + return ret; +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, int type) +{ + struct spec *spec; + + spec = lookup_common(rec, key, type, false); + if (spec) + return &spec->lr; + return NULL; +} + +static bool partial_match(struct selabel_handle *rec, const char *key) +{ + return lookup_common(rec, key, 0, true) ? true : false; +} + +static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec, + const char *key, + const char **aliases, + int type) +{ + size_t n, i; + int best = -1; + struct spec **specs; + size_t prefix_len = 0; + struct selabel_lookup_rec *lr = NULL; + + if (!aliases || !aliases[0]) + return lookup(rec, key, type); + + for (n = 0; aliases[n]; n++) + ; + + specs = calloc(n+1, sizeof(struct spec *)); + if (!specs) + return NULL; + specs[0] = lookup_common(rec, key, type, false); + if (specs[0]) { + if (!specs[0]->hasMetaChars) { + /* exact match on key */ + lr = &specs[0]->lr; + goto out; + } + best = 0; + prefix_len = specs[0]->prefix_len; + } + for (i = 1; i <= n; i++) { + specs[i] = lookup_common(rec, aliases[i-1], type, false); + if (specs[i]) { + if (!specs[i]->hasMetaChars) { + /* exact match on alias */ + lr = &specs[i]->lr; + goto out; + } + if (specs[i]->prefix_len > prefix_len) { + best = i; + prefix_len = specs[i]->prefix_len; + } + } + } + + if (best >= 0) { + /* longest fixed prefix match on key or alias */ + lr = &specs[best]->lr; + } else { + errno = ENOENT; + } + +out: + free(specs); + return lr; +} + +static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j) +{ + selinux_log(SELINUX_INFO, + "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", + reason, + i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, + j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); + return SELABEL_INCOMPARABLE; +} + +static enum selabel_cmp_result cmp(struct selabel_handle *h1, + struct selabel_handle *h2) +{ + struct saved_data *data1 = (struct saved_data *)h1->data; + struct saved_data *data2 = (struct saved_data *)h2->data; + unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec; + struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr; + struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr; + bool skipped1 = false, skipped2 = false; + + i = 0; + j = 0; + while (i < nspec1 && j < nspec2) { + struct spec *spec1 = &spec_arr1[i]; + struct spec *spec2 = &spec_arr2[j]; + + /* + * Because sort_specs() moves exact pathnames to the + * end, we might need to skip over additional regex + * entries that only exist in one of the configurations. + */ + if (!spec1->hasMetaChars && spec2->hasMetaChars) { + j++; + skipped2 = true; + continue; + } + + if (spec1->hasMetaChars && !spec2->hasMetaChars) { + i++; + skipped1 = true; + continue; + } + + if (spec1->regex && spec2->regex) { + if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){ + return incomp(spec1, spec2, "regex", i, j); + } + } else { + if (strcmp(spec1->regex_str, spec2->regex_str)) + return incomp(spec1, spec2, "regex_str", i, j); + } + + if (spec1->mode != spec2->mode) + return incomp(spec1, spec2, "mode", i, j); + + if (spec1->stem_id == -1 && spec2->stem_id != -1) + return incomp(spec1, spec2, "stem_id", i, j); + if (spec2->stem_id == -1 && spec1->stem_id != -1) + return incomp(spec1, spec2, "stem_id", i, j); + if (spec1->stem_id != -1 && spec2->stem_id != -1) { + struct stem *stem1 = &stem_arr1[spec1->stem_id]; + struct stem *stem2 = &stem_arr2[spec2->stem_id]; + if (stem1->len != stem2->len || + strncmp(stem1->buf, stem2->buf, stem1->len)) + return incomp(spec1, spec2, "stem", i, j); + } + + if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw)) + return incomp(spec1, spec2, "ctx_raw", i, j); + + i++; + j++; + } + + if ((skipped1 || i < nspec1) && !skipped2) + return SELABEL_SUPERSET; + if ((skipped2 || j < nspec2) && !skipped1) + return SELABEL_SUBSET; + if (skipped1 && skipped2) + return SELABEL_INCOMPARABLE; + return SELABEL_EQUAL; +} + + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, nspec = data->nspec; + struct spec *spec_arr = data->spec_arr; + + for (i = 0; i < nspec; i++) { + if (spec_arr[i].matches == 0) { + if (spec_arr[i].type_str) { + COMPAT_LOG(SELINUX_WARNING, + "Warning! No matches for (%s, %s, %s)\n", + spec_arr[i].regex_str, + spec_arr[i].type_str, + spec_arr[i].lr.ctx_raw); + } else { + COMPAT_LOG(SELINUX_WARNING, + "Warning! No matches for (%s, %s)\n", + spec_arr[i].regex_str, + spec_arr[i].lr.ctx_raw); + } + } + } +} + +int selabel_file_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &lookup; + rec->func_partial_match = &partial_match; + rec->func_lookup_best_match = &lookup_best_match; + rec->func_cmp = &cmp; + + return init(rec, opts, nopts); +} diff --git a/src/label_file.h b/src/label_file.h new file mode 100644 index 0000000..47859ba --- /dev/null +++ b/src/label_file.h @@ -0,0 +1,535 @@ +#ifndef _SELABEL_FILE_H_ +#define _SELABEL_FILE_H_ + +#include +#include +#include + +#include + +/* + * regex.h/c were introduced to hold all dependencies on the regular + * expression back-end when we started supporting PCRE2. regex.h defines a + * minimal interface required by libselinux, so that the remaining code + * can be agnostic about the underlying implementation. + */ +#include "regex.h" + +#include "callbacks.h" +#include "label_internal.h" +#include "selinux_internal.h" + +#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a + +/* Version specific changes */ +#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 +#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 +#define SELINUX_COMPILED_FCONTEXT_MODE 3 +#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 +#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5 + +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \ + SELINUX_COMPILED_FCONTEXT_REGEX_ARCH + +struct selabel_sub { + char *src; + int slen; + char *dst; + struct selabel_sub *next; +}; + +/* A file security context specification. */ +struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *regex_str; /* regular expession string for diagnostics */ + char *type_str; /* type string for diagnostic messages */ + struct regex_data * regex; /* backend dependent regular expression data */ + bool regex_compiled; /* bool to indicate if the regex is compiled */ + pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */ + mode_t mode; /* mode format value */ + int matches; /* number of matching pathnames */ + int stem_id; /* indicates which stem-compression item */ + char hasMetaChars; /* regular expression has meta-chars */ + char from_mmap; /* this spec is from an mmap of the data */ + size_t prefix_len; /* length of fixed path prefix */ +}; + +/* A regular expression stem */ +struct stem { + char *buf; + int len; + char from_mmap; +}; + +/* Where we map the file in during selabel_open() */ +struct mmap_area { + void *addr; /* Start addr + len used to release memory at close */ + size_t len; + void *next_addr; /* Incremented by next_entry() */ + size_t next_len; /* Decremented by next_entry() */ + struct mmap_area *next; +}; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications, initially in the same order as in + * the specification file. Sorting occurs based on hasMetaChars. + */ + struct spec *spec_arr; + unsigned int nspec; + unsigned int alloc_specs; + + /* + * The array of regular expression stems. + */ + struct stem *stem_arr; + int num_stems; + int alloc_stems; + struct mmap_area *mmap_areas; + + /* substitution support */ + struct selabel_sub *dist_subs; + struct selabel_sub *subs; +}; + +static inline mode_t string_to_mode(char *mode) +{ + size_t len; + + if (!mode) + return 0; + len = strlen(mode); + if (mode[0] != '-' || len != 2) + return -1; + switch (mode[1]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case '-': + return S_IFREG; + default: + return -1; + } + /* impossible to get here */ + return 0; +} + +static inline int grow_specs(struct saved_data *data) +{ + struct spec *specs; + size_t new_specs, total_specs; + + if (data->nspec < data->alloc_specs) + return 0; + + new_specs = data->nspec + 16; + total_specs = data->nspec + new_specs; + + specs = realloc(data->spec_arr, total_specs * sizeof(*specs)); + if (!specs) { + perror("realloc"); + return -1; + } + + /* blank the new entries */ + memset(&specs[data->nspec], 0, new_specs * sizeof(*specs)); + + data->spec_arr = specs; + data->alloc_specs = total_specs; + return 0; +} + +/* Determine if the regular expression specification has any meta characters. */ +static inline void spec_hasMetaChars(struct spec *spec) +{ + char *c; + int len; + char *end; + + c = spec->regex_str; + len = strlen(spec->regex_str); + end = c + len; + + spec->hasMetaChars = 0; + spec->prefix_len = len; + + /* Look at each character in the RE specification string for a + * meta character. Return when any meta character reached. */ + while (c < end) { + switch (*c) { + case '.': + case '^': + case '$': + case '?': + case '*': + case '+': + case '|': + case '[': + case '(': + case '{': + spec->hasMetaChars = 1; + spec->prefix_len = c - spec->regex_str; + return; + case '\\': /* skip the next character */ + c++; + break; + default: + break; + + } + c++; + } +} + +/* Move exact pathname specifications to the end. */ +static inline int sort_specs(struct saved_data *data) +{ + struct spec *spec_copy; + struct spec spec; + unsigned int i; + int front, back; + size_t len = sizeof(*spec_copy); + + spec_copy = malloc(len * data->nspec); + if (!spec_copy) + return -1; + + /* first move the exact pathnames to the back */ + front = 0; + back = data->nspec - 1; + for (i = 0; i < data->nspec; i++) { + if (data->spec_arr[i].hasMetaChars) + memcpy(&spec_copy[front++], &data->spec_arr[i], len); + else + memcpy(&spec_copy[back--], &data->spec_arr[i], len); + } + + /* + * now the exact pathnames are at the end, but they are in the reverse + * order. Since 'front' is now the first of the 'exact' we can run + * that part of the array switching the front and back element. + */ + back = data->nspec - 1; + while (front < back) { + /* save the front */ + memcpy(&spec, &spec_copy[front], len); + /* move the back to the front */ + memcpy(&spec_copy[front], &spec_copy[back], len); + /* put the old front in the back */ + memcpy(&spec_copy[back], &spec, len); + front++; + back--; + } + + free(data->spec_arr); + data->spec_arr = spec_copy; + + return 0; +} + +/* Return the length of the text that can be considered the stem, returns 0 + * if there is no identifiable stem */ +static inline int get_stem_from_spec(const char *const buf) +{ + const char *tmp = strchr(buf + 1, '/'); + const char *ind; + + if (!tmp) + return 0; + + for (ind = buf; ind < tmp; ind++) { + if (strchr(".^$?*+|[({", (int)*ind)) + return 0; + } + return tmp - buf; +} + +/* + * return the stemid given a string and a length + */ +static inline int find_stem(struct saved_data *data, const char *buf, + int stem_len) +{ + int i; + + for (i = 0; i < data->num_stems; i++) { + if (stem_len == data->stem_arr[i].len && + !strncmp(buf, data->stem_arr[i].buf, stem_len)) + return i; + } + + return -1; +} + +/* returns the index of the new stored object */ +static inline int store_stem(struct saved_data *data, char *buf, int stem_len) +{ + int num = data->num_stems; + + if (data->alloc_stems == num) { + struct stem *tmp_arr; + int alloc_stems = data->alloc_stems * 2 + 16; + tmp_arr = realloc(data->stem_arr, + sizeof(*tmp_arr) * alloc_stems); + if (!tmp_arr) { + free(buf); + return -1; + } + data->alloc_stems = alloc_stems; + data->stem_arr = tmp_arr; + } + data->stem_arr[num].len = stem_len; + data->stem_arr[num].buf = buf; + data->stem_arr[num].from_mmap = 0; + data->num_stems++; + + return num; +} + +/* find the stem of a file spec, returns the index into stem_arr for a new + * or existing stem, (or -1 if there is no possible stem - IE for a file in + * the root directory or a regex that is too complex for us). */ +static inline int find_stem_from_spec(struct saved_data *data, const char *buf) +{ + int stem_len = get_stem_from_spec(buf); + int stemid; + char *stem; + + if (!stem_len) + return -1; + + stemid = find_stem(data, buf, stem_len); + if (stemid >= 0) + return stemid; + + /* not found, allocate a new one */ + stem = strndup(buf, stem_len); + if (!stem) + return -1; + + return store_stem(data, stem, stem_len); +} + +/* This will always check for buffer over-runs and either read the next entry + * if buf != NULL or skip over the entry (as these areas are mapped in the + * current buffer). */ +static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes) +{ + if (bytes > fp->next_len) + return -1; + + if (buf) + memcpy(buf, fp->next_addr, bytes); + + fp->next_addr = (char *)fp->next_addr + bytes; + fp->next_len -= bytes; + return 0; +} + +static inline int compile_regex(struct saved_data *data, struct spec *spec, + const char **errbuf) +{ + char *reg_buf, *anchored_regex, *cp; + struct regex_error_data error_data; + static char regex_error_format_buffer[256]; + struct stem *stem_arr = data->stem_arr; + size_t len; + int rc; + bool regex_compiled; + + /* We really want pthread_once() here, but since its + * init_routine does not take a parameter, it's not possible + * to use, so we generate the same effect with atomics and a + * mutex */ +#ifdef __ATOMIC_RELAXED + regex_compiled = + __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE); +#else + /* GCC <4.7 */ + __sync_synchronize(); + regex_compiled = spec->regex_compiled; +#endif + if (regex_compiled) { + return 0; /* already done */ + } + + __pthread_mutex_lock(&spec->regex_lock); + /* Check if another thread compiled the regex while we waited + * on the mutex */ +#ifdef __ATOMIC_RELAXED + regex_compiled = + __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE); +#else + /* GCC <4.7 */ + __sync_synchronize(); + regex_compiled = spec->regex_compiled; +#endif + if (regex_compiled) { + __pthread_mutex_unlock(&spec->regex_lock); + return 0; + } + + /* Skip the fixed stem. */ + reg_buf = spec->regex_str; + if (spec->stem_id >= 0) + reg_buf += stem_arr[spec->stem_id].len; + + /* Anchor the regular expression. */ + len = strlen(reg_buf); + cp = anchored_regex = malloc(len + 3); + if (!anchored_regex) { + if (errbuf) + *errbuf = "out of memory"; + __pthread_mutex_unlock(&spec->regex_lock); + return -1; + } + + /* Create ^...$ regexp. */ + *cp++ = '^'; + memcpy(cp, reg_buf, len); + cp += len; + *cp++ = '$'; + *cp = '\0'; + + /* Compile the regular expression. */ + rc = regex_prepare_data(&spec->regex, anchored_regex, &error_data); + free(anchored_regex); + if (rc < 0) { + if (errbuf) { + regex_format_error(&error_data, + regex_error_format_buffer, + sizeof(regex_error_format_buffer)); + *errbuf = ®ex_error_format_buffer[0]; + } + __pthread_mutex_unlock(&spec->regex_lock); + return -1; + } + + /* Done. */ +#ifdef __ATOMIC_RELAXED + __atomic_store_n(&spec->regex_compiled, true, __ATOMIC_RELEASE); +#else + /* GCC <4.7 */ + spec->regex_compiled = true; + __sync_synchronize(); +#endif + __pthread_mutex_unlock(&spec->regex_lock); + return 0; +} + +/* This service is used by label_file.c process_file() and + * utils/sefcontext_compile.c */ +static inline int process_line(struct selabel_handle *rec, + const char *path, const char *prefix, + char *line_buf, unsigned lineno) +{ + int items, len, rc; + char *regex = NULL, *type = NULL, *context = NULL; + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec_arr; + unsigned int nspec = data->nspec; + const char *errbuf = NULL; + + items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context); + if (items < 0) { + rc = errno; + selinux_log(SELINUX_ERROR, + "%s: line %u error due to: %s\n", path, + lineno, errbuf ?: strerror(errno)); + errno = rc; + return -1; + } + + if (items == 0) + return items; + + if (items < 2) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u is missing fields\n", path, + lineno); + if (items == 1) + free(regex); + errno = EINVAL; + return -1; + } else if (items == 2) { + /* The type field is optional. */ + context = type; + type = 0; + } + + len = get_stem_from_spec(regex); + if (len && prefix && strncmp(prefix, regex, len)) { + /* Stem of regex does not match requested prefix, discard. */ + free(regex); + free(type); + free(context); + return 0; + } + + rc = grow_specs(data); + if (rc) + return rc; + + spec_arr = data->spec_arr; + + /* process and store the specification in spec. */ + spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); + spec_arr[nspec].regex_str = regex; + __pthread_mutex_init(&spec_arr[nspec].regex_lock, NULL); + spec_arr[nspec].regex_compiled = false; + + spec_arr[nspec].type_str = type; + spec_arr[nspec].mode = 0; + + spec_arr[nspec].lr.ctx_raw = context; + spec_arr[nspec].lr.lineno = lineno; + + /* + * bump data->nspecs to cause closef() to cover it in its free + * but do not bump nspec since it's used below. + */ + data->nspec++; + + if (rec->validating + && compile_regex(data, &spec_arr[nspec], &errbuf)) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u has invalid regex %s: %s\n", + path, lineno, regex, errbuf); + errno = EINVAL; + return -1; + } + + if (type) { + mode_t mode = string_to_mode(type); + + if (mode == (mode_t)-1) { + COMPAT_LOG(SELINUX_ERROR, + "%s: line %u has invalid file type %s\n", + path, lineno, type); + errno = EINVAL; + return -1; + } + spec_arr[nspec].mode = mode; + } + + /* Determine if specification has + * any meta characters in the RE */ + spec_hasMetaChars(&spec_arr[nspec]); + + if (strcmp(context, "<>") && rec->validating) + return compat_validate(rec, &spec_arr[nspec].lr, path, lineno); + + return 0; +} + +#endif /* _SELABEL_FILE_H_ */ diff --git a/src/label_internal.h b/src/label_internal.h new file mode 100644 index 0000000..0e02055 --- /dev/null +++ b/src/label_internal.h @@ -0,0 +1,141 @@ +/* + * This file describes the internal interface used by the labeler + * for calling the user-supplied memory allocation, validation, + * and locking routine. + * + * Author : Eamon Walsh + */ +#ifndef _SELABEL_INTERNAL_H_ +#define _SELABEL_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include "dso.h" +#include "sha1.h" + +#if defined(ANDROID) || defined(__APPLE__) +// Android and Mac do not have fgets_unlocked() +#define fgets_unlocked(buf, size, fp) fgets(buf, size, fp) +#endif + +/* + * Installed backends + */ +int selabel_file_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_media_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_x_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_db_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_property_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; +int selabel_service_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) hidden; + +/* + * Labeling internal structures + */ + +/* + * Calculate an SHA1 hash of all the files used to build the specs. + * The hash value is held in rec->digest if SELABEL_OPT_DIGEST set. To + * calculate the hash the hashbuf will hold a concatenation of all the files + * used. This is released once the value has been calculated. + */ +#define DIGEST_SPECFILE_SIZE SHA1_HASH_SIZE +#define DIGEST_FILES_MAX 8 +struct selabel_digest { + unsigned char *digest; /* SHA1 digest of specfiles */ + unsigned char *hashbuf; /* buffer to hold specfiles */ + size_t hashbuf_size; /* buffer size */ + size_t specfile_cnt; /* how many specfiles processed */ + char **specfile_list; /* and their names */ +}; + +extern int digest_add_specfile(struct selabel_digest *digest, FILE *fp, + char *from_addr, + size_t buf_len, + const char *path); +extern void digest_gen_hash(struct selabel_digest *digest); + +struct selabel_lookup_rec { + char * ctx_raw; + char * ctx_trans; + int validated; + unsigned lineno; +}; + +struct selabel_handle { + /* arguments that were passed to selabel_open */ + unsigned int backend; + int validating; + + /* labeling operations */ + struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h, + const char *key, int type); + void (*func_close) (struct selabel_handle *h); + void (*func_stats) (struct selabel_handle *h); + bool (*func_partial_match) (struct selabel_handle *h, const char *key); + struct selabel_lookup_rec *(*func_lookup_best_match) + (struct selabel_handle *h, + const char *key, + const char **aliases, + int type); + enum selabel_cmp_result (*func_cmp)(struct selabel_handle *h1, + struct selabel_handle *h2); + + /* supports backend-specific state information */ + void *data; + + /* + * The main spec file used. Note for file contexts the local and/or + * homedirs could also have been used to resolve a context. + */ + char *spec_file; + + /* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */ + struct selabel_digest *digest; +}; + +/* + * Validation function + */ +extern int +selabel_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts) hidden; + +/* + * Compatibility support + */ +extern int myprintf_compat; +extern void __attribute__ ((format(printf, 1, 2))) +(*myprintf) (const char *fmt, ...) hidden; + +#define COMPAT_LOG(type, fmt...) if (myprintf_compat) \ + myprintf(fmt); \ + else \ + selinux_log(type, fmt); + +extern int +compat_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts, + const char *path, unsigned lineno) hidden; + +/* + * The read_spec_entries function may be used to + * replace sscanf to read entries from spec files. + */ +extern int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...); + +#endif /* _SELABEL_INTERNAL_H_ */ diff --git a/src/label_media.c b/src/label_media.c new file mode 100644 index 0000000..d202e5d --- /dev/null +++ b/src/label_media.c @@ -0,0 +1,226 @@ +/* + * Media contexts backend for labeling system + * + * Author : Eamon Walsh + */ + +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +/* + * Internals + */ + +/* A context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *key; /* key string */ + int matches; /* number of matches made during operation */ +} spec_t; + +struct saved_data { + unsigned int nspec; + spec_t *spec_arr; +}; + +static int process_line(const char *path, char *line_buf, int pass, + unsigned lineno, struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + int items; + char *buf_p; + char *key, *context; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == 0) + return 0; + items = sscanf(line_buf, "%ms %ms ", &key, &context); + if (items < 2) { + selinux_log(SELINUX_WARNING, + "%s: line %u is missing fields, skipping\n", path, + lineno); + if (items == 1) + free(key); + return 0; + } + + if (pass == 1) { + data->spec_arr[data->nspec].key = key; + data->spec_arr[data->nspec].lr.ctx_raw = context; + } + + data->nspec++; + if (pass == 0) { + free(key); + free(context); + } + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + FILE *fp; + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + int status = -1; + unsigned int lineno, pass, maxnspec; + struct stat sb; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + /* Open the specification file. */ + if (!path) + path = selinux_media_context_path(); + if ((fp = fopen(path, "re")) == NULL) + return -1; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + rec->spec_file = strdup(path); + + /* + * Perform two passes over the specification file. + * The first pass counts the number of specifications and + * performs simple validation of the input. At the end + * of the first pass, the spec array is allocated. + * The second pass performs detailed validation of the input + * and fills in the spec array. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + lineno = 0; + data->nspec = 0; + while (getline(&line_buf, &line_len, fp) > 0 && + data->nspec < maxnspec) { + if (process_line(path, line_buf, pass, ++lineno, rec)) + goto finish; + } + lineno = 0; + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + data->spec_arr = malloc(sizeof(spec_t)*data->nspec); + if (data->spec_arr == NULL) + goto finish; + memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + free(line_buf); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void close(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec, *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &spec_arr[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (spec_arr) + free(spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, + int type __attribute__((unused))) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + if (!strncmp(spec_arr[i].key, key, strlen(key) + 1)) + break; + if (!strncmp(spec_arr[i].key, "*", 2)) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + return NULL; + } + + spec_arr[i].matches++; + return &spec_arr[i].lr; +} + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < data->nspec; i++) + total += data->spec_arr[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + data->nspec, total); +} + +int selabel_media_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &close; + rec->func_lookup = &lookup; + rec->func_stats = &stats; + + return init(rec, opts, nopts); +} diff --git a/src/label_support.c b/src/label_support.c new file mode 100644 index 0000000..26f9ef1 --- /dev/null +++ b/src/label_support.c @@ -0,0 +1,192 @@ +/* + * This file contains helper functions for labeling support. + * + * Author : Richard Haines + */ + +#include +#include +#include +#include +#include +#include +#include +#include "label_internal.h" + +/* + * Read an entry from a spec file (e.g. file_contexts) + * entry - Buffer to allocate for the entry. + * ptr - current location of the line to be processed. + * returns - 0 on success and *entry is set to be a null + * terminated value. On Error it returns -1 and + * errno will be set. + * + */ +static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf) +{ + *entry = NULL; + char *tmp_buf = NULL; + + while (isspace(**ptr) && **ptr != '\0') + (*ptr)++; + + tmp_buf = *ptr; + *len = 0; + + while (!isspace(**ptr) && **ptr != '\0') { + if (!isascii(**ptr)) { + errno = EINVAL; + *errbuf = "Non-ASCII characters found"; + return -1; + } + (*ptr)++; + (*len)++; + } + + if (*len) { + *entry = strndup(tmp_buf, *len); + if (!*entry) + return -1; + } + + return 0; +} + +/* + * line_buf - Buffer containing the spec entries . + * errbuf - Double pointer used for passing back specific error messages. + * num_args - The number of spec parameter entries to process. + * ... - A 'char **spec_entry' for each parameter. + * returns - The number of items processed. On error, it returns -1 with errno + * set and may set errbuf to a specific error message. + * + * This function calls read_spec_entry() to do the actual string processing. + * As such, can return anything from that function as well. + */ +int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) +{ + char **spec_entry, *buf_p; + int len, rc, items, entry_len = 0; + va_list ap; + + *errbuf = NULL; + + len = strlen(line_buf); + if (line_buf[len - 1] == '\n') + line_buf[len - 1] = '\0'; + else + /* Handle case if line not \n terminated by bumping + * the len for the check below (as the line is NUL + * terminated by getline(3)) */ + len++; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == '\0') + return 0; + + /* Process the spec file entries */ + va_start(ap, num_args); + + items = 0; + while (items < num_args) { + spec_entry = va_arg(ap, char **); + + if (len - 1 == buf_p - line_buf) { + va_end(ap); + return items; + } + + rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf); + if (rc < 0) { + va_end(ap); + return rc; + } + if (entry_len) + items++; + } + va_end(ap); + return items; +} + +/* Once all the specfiles are in the hash_buf, generate the hash. */ +void hidden digest_gen_hash(struct selabel_digest *digest) +{ + Sha1Context context; + + /* If SELABEL_OPT_DIGEST not set then just return */ + if (!digest) + return; + + Sha1Initialise(&context); + Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); + Sha1Finalise(&context, (SHA1_HASH *)digest->digest); + free(digest->hashbuf); + digest->hashbuf = NULL; + return; +} + +/** + * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true + * then generate the hash. + * @digest: pointer to the selabel_digest struct + * @fp: file pointer for fread(3) or NULL if not. + * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for + * mmap(3) files). + * @buf_len: length of buffer to copy. + * @path: pointer to the specfile. + * + * Return %0 on success, -%1 with @errno set on failure. + */ +int hidden digest_add_specfile(struct selabel_digest *digest, FILE *fp, + char *from_addr, size_t buf_len, + const char *path) +{ + unsigned char *tmp_buf; + + /* If SELABEL_OPT_DIGEST not set then just return */ + if (!digest) + return 0; + + if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { + errno = EOVERFLOW; + return -1; + } + digest->hashbuf_size += buf_len; + + tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size); + if (!tmp_buf) + return -1; + + digest->hashbuf = tmp_buf; + + if (fp) { + rewind(fp); + if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len), + 1, buf_len, fp) != buf_len) + return -1; + + rewind(fp); + } else if (from_addr) { + tmp_buf = memcpy(digest->hashbuf + + (digest->hashbuf_size - buf_len), + from_addr, buf_len); + if (!tmp_buf) + return -1; + } + /* Now add path to list */ + digest->specfile_list[digest->specfile_cnt] = strdup(path); + if (!digest->specfile_list[digest->specfile_cnt]) + return -1; + + digest->specfile_cnt++; + if (digest->specfile_cnt > DIGEST_FILES_MAX) { + errno = EOVERFLOW; + return -1; + } + + return 0; +} diff --git a/src/label_x.c b/src/label_x.c new file mode 100644 index 0000000..9674529 --- /dev/null +++ b/src/label_x.c @@ -0,0 +1,251 @@ +/* + * Media contexts backend for X contexts + * + * Author : Eamon Walsh + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +/* + * Internals + */ + +/* A context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *key; /* key string */ + int type; /* type of record (prop, ext, client) */ + int matches; /* number of matches made during operation */ +} spec_t; + +struct saved_data { + unsigned int nspec; + spec_t *spec_arr; +}; + +static int process_line(const char *path, char *line_buf, int pass, + unsigned lineno, struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + int items; + char *buf_p; + char *type, *key, *context; + + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == 0) + return 0; + items = sscanf(line_buf, "%ms %ms %ms ", &type, &key, &context); + if (items < 3) { + selinux_log(SELINUX_WARNING, + "%s: line %u is missing fields, skipping\n", path, + lineno); + if (items > 0) + free(type); + if (items > 1) + free(key); + return 0; + } + + if (pass == 1) { + /* Convert the type string to a mode format */ + if (!strcmp(type, "property")) + data->spec_arr[data->nspec].type = SELABEL_X_PROP; + else if (!strcmp(type, "extension")) + data->spec_arr[data->nspec].type = SELABEL_X_EXT; + else if (!strcmp(type, "client")) + data->spec_arr[data->nspec].type = SELABEL_X_CLIENT; + else if (!strcmp(type, "event")) + data->spec_arr[data->nspec].type = SELABEL_X_EVENT; + else if (!strcmp(type, "selection")) + data->spec_arr[data->nspec].type = SELABEL_X_SELN; + else if (!strcmp(type, "poly_property")) + data->spec_arr[data->nspec].type = SELABEL_X_POLYPROP; + else if (!strcmp(type, "poly_selection")) + data->spec_arr[data->nspec].type = SELABEL_X_POLYSELN; + else { + selinux_log(SELINUX_WARNING, + "%s: line %u has invalid object type %s\n", + path, lineno, type); + return 0; + } + data->spec_arr[data->nspec].key = key; + data->spec_arr[data->nspec].lr.ctx_raw = context; + free(type); + } + + data->nspec++; + if (pass == 0) { + free(type); + free(key); + free(context); + } + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + FILE *fp; + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + char *line_buf = NULL; + size_t line_len = 0; + int status = -1; + unsigned int lineno, pass, maxnspec; + struct stat sb; + + /* Process arguments */ + while (n--) + switch(opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + /* Open the specification file. */ + if (!path) + path = selinux_x_context_path(); + if ((fp = fopen(path, "re")) == NULL) + return -1; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + rec->spec_file = strdup(path); + + /* + * Perform two passes over the specification file. + * The first pass counts the number of specifications and + * performs simple validation of the input. At the end + * of the first pass, the spec array is allocated. + * The second pass performs detailed validation of the input + * and fills in the spec array. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + lineno = 0; + data->nspec = 0; + while (getline(&line_buf, &line_len, fp) > 0 && + data->nspec < maxnspec) { + if (process_line(path, line_buf, pass, ++lineno, rec)) + goto finish; + } + lineno = 0; + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + data->spec_arr = malloc(sizeof(spec_t)*data->nspec); + if (data->spec_arr == NULL) + goto finish; + memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + free(line_buf); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void close(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec, *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &spec_arr[i]; + free(spec->key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (spec_arr) + free(spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, int type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + if (spec_arr[i].type != type) + continue; + if (!fnmatch(spec_arr[i].key, key, 0)) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + return NULL; + } + + spec_arr[i].matches++; + return &spec_arr[i].lr; +} + +static void stats(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + unsigned int i, total = 0; + + for (i = 0; i < data->nspec; i++) + total += data->spec_arr[i].matches; + + selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", + data->nspec, total); +} + +int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &close; + rec->func_lookup = &lookup; + rec->func_stats = &stats; + + return init(rec, opts, nopts); +} diff --git a/src/lgetfilecon.c b/src/lgetfilecon.c new file mode 100644 index 0000000..db67bc6 --- /dev/null +++ b/src/lgetfilecon.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +int lgetfilecon_raw(const char *path, char ** context) +{ + char *buf; + ssize_t size; + ssize_t ret; + + size = INITCONTEXTLEN + 1; + buf = malloc(size); + if (!buf) + return -1; + memset(buf, 0, size); + + ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + if (ret < 0 && errno == ERANGE) { + char *newbuf; + + size = lgetxattr(path, XATTR_NAME_SELINUX, NULL, 0); + if (size < 0) + goto out; + + size++; + newbuf = realloc(buf, size); + if (!newbuf) + goto out; + + buf = newbuf; + memset(buf, 0, size); + ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); + } + out: + if (ret == 0) { + /* Re-map empty attribute values to errors. */ + errno = ENOTSUP; + ret = -1; + } + if (ret < 0) + free(buf); + else + *context = buf; + return ret; +} + +hidden_def(lgetfilecon_raw) + +int lgetfilecon(const char *path, char ** context) +{ + int ret; + char * rcontext = NULL; + + *context = NULL; + + ret = lgetfilecon_raw(path, &rcontext); + + if (ret > 0) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + if (ret >= 0 && *context) + return strlen(*context) + 1; + return ret; +} diff --git a/src/libselinux.pc.in b/src/libselinux.pc.in new file mode 100644 index 0000000..7c66b1f --- /dev/null +++ b/src/libselinux.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: libselinux +Description: SELinux utility library +Version: @VERSION@ +URL: http://userspace.selinuxproject.org/ +Requires.private: libsepol @PCRE_MODULE@ +Libs: -L${libdir} -lselinux +Cflags: -I${includedir} diff --git a/src/load_policy.c b/src/load_policy.c new file mode 100644 index 0000000..20052be --- /dev/null +++ b/src/load_policy.c @@ -0,0 +1,473 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#ifndef ANDROID +#include +#include +#endif +#include +#include "policy.h" +#include + +#ifndef MNT_DETACH +#define MNT_DETACH 2 +#endif + +int security_load_policy(void *data, size_t len) +{ + char path[PATH_MAX]; + int fd, ret; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/load", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + ret = write(fd, data, len); + close(fd); + if (ret < 0) + return -1; + return 0; +} + +hidden_def(security_load_policy) + +#ifndef ANDROID +int load_setlocaldefs hidden = 1; + +#undef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +int selinux_mkload_policy(int preservebools) +{ + int kernvers = security_policyvers(); + int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers; + int setlocaldefs = load_setlocaldefs; + char path[PATH_MAX]; + struct stat sb; + struct utsname uts; + size_t size; + void *map, *data; + int fd, rc = -1, prot; + sepol_policydb_t *policydb; + sepol_policy_file_t *pf; + int usesepol = 0; + int (*vers_max)(void) = NULL; + int (*vers_min)(void) = NULL; + int (*policy_file_create)(sepol_policy_file_t **) = NULL; + void (*policy_file_free)(sepol_policy_file_t *) = NULL; + void (*policy_file_set_mem)(sepol_policy_file_t *, char*, size_t) = NULL; + int (*policydb_create)(sepol_policydb_t **) = NULL; + void (*policydb_free)(sepol_policydb_t *) = NULL; + int (*policydb_read)(sepol_policydb_t *, sepol_policy_file_t *) = NULL; + int (*policydb_set_vers)(sepol_policydb_t *, unsigned int) = NULL; + int (*policydb_to_image)(sepol_handle_t *, sepol_policydb_t *, void **, size_t *) = NULL; + int (*genbools_array)(void *data, size_t len, char **names, int *values, int nel) = NULL; + int (*genusers)(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen) = NULL; + int (*genbools)(void *data, size_t len, const char *boolpath) = NULL; + +#ifdef SHARED + char *errormsg = NULL; + void *libsepolh = NULL; + libsepolh = dlopen("libsepol.so.1", RTLD_NOW); + if (libsepolh) { + usesepol = 1; + dlerror(); +#define DLERR() if ((errormsg = dlerror())) goto dlclose; + vers_max = dlsym(libsepolh, "sepol_policy_kern_vers_max"); + DLERR(); + vers_min = dlsym(libsepolh, "sepol_policy_kern_vers_min"); + DLERR(); + + policy_file_create = dlsym(libsepolh, "sepol_policy_file_create"); + DLERR(); + policy_file_free = dlsym(libsepolh, "sepol_policy_file_free"); + DLERR(); + policy_file_set_mem = dlsym(libsepolh, "sepol_policy_file_set_mem"); + DLERR(); + policydb_create = dlsym(libsepolh, "sepol_policydb_create"); + DLERR(); + policydb_free = dlsym(libsepolh, "sepol_policydb_free"); + DLERR(); + policydb_read = dlsym(libsepolh, "sepol_policydb_read"); + DLERR(); + policydb_set_vers = dlsym(libsepolh, "sepol_policydb_set_vers"); + DLERR(); + policydb_to_image = dlsym(libsepolh, "sepol_policydb_to_image"); + DLERR(); + genbools_array = dlsym(libsepolh, "sepol_genbools_array"); + DLERR(); + genusers = dlsym(libsepolh, "sepol_genusers"); + DLERR(); + genbools = dlsym(libsepolh, "sepol_genbools"); + DLERR(); + +#undef DLERR + } +#else + usesepol = 1; + vers_max = sepol_policy_kern_vers_max; + vers_min = sepol_policy_kern_vers_min; + policy_file_create = sepol_policy_file_create; + policy_file_free = sepol_policy_file_free; + policy_file_set_mem = sepol_policy_file_set_mem; + policydb_create = sepol_policydb_create; + policydb_free = sepol_policydb_free; + policydb_read = sepol_policydb_read; + policydb_set_vers = sepol_policydb_set_vers; + policydb_to_image = sepol_policydb_to_image; + genbools_array = sepol_genbools_array; + genusers = sepol_genusers; + genbools = sepol_genbools; + +#endif + + /* + * Check whether we need to support local boolean and user definitions. + */ + if (setlocaldefs) { + if (access(selinux_booleans_path(), F_OK) == 0) + goto checkbool; + snprintf(path, sizeof path, "%s.local", selinux_booleans_path()); + if (access(path, F_OK) == 0) + goto checkbool; + snprintf(path, sizeof path, "%s/local.users", selinux_users_path()); + if (access(path, F_OK) == 0) + goto checkbool; + /* No local definition files, so disable setlocaldefs. */ + setlocaldefs = 0; + } + +checkbool: + /* + * As of Linux 2.6.22, the kernel preserves boolean + * values across a reload, so we do not need to + * preserve them in userspace. + */ + if (preservebools && uname(&uts) == 0 && strverscmp(uts.release, "2.6.22") >= 0) + preservebools = 0; + + if (usesepol) { + maxvers = vers_max(); + minvers = vers_min(); + if (!setlocaldefs && !preservebools) + maxvers = max(kernvers, maxvers); + } + + vers = maxvers; + search: + snprintf(path, sizeof(path), "%s.%d", + selinux_binary_policy_path(), vers); + fd = open(path, O_RDONLY | O_CLOEXEC); + while (fd < 0 && errno == ENOENT + && --vers >= minvers) { + /* Check prior versions to see if old policy is available */ + snprintf(path, sizeof(path), "%s.%d", + selinux_binary_policy_path(), vers); + fd = open(path, O_RDONLY | O_CLOEXEC); + } + if (fd < 0) { + fprintf(stderr, + "SELinux: Could not open policy file <= %s.%d: %s\n", + selinux_binary_policy_path(), maxvers, strerror(errno)); + goto dlclose; + } + + if (fstat(fd, &sb) < 0) { + fprintf(stderr, + "SELinux: Could not stat policy file %s: %s\n", + path, strerror(errno)); + goto close; + } + + prot = PROT_READ; + if (setlocaldefs || preservebools) + prot |= PROT_WRITE; + + size = sb.st_size; + data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, + "SELinux: Could not map policy file %s: %s\n", + path, strerror(errno)); + goto close; + } + + if (vers > kernvers && usesepol) { + /* Need to downgrade to kernel-supported version. */ + if (policy_file_create(&pf)) + goto unmap; + if (policydb_create(&policydb)) { + policy_file_free(pf); + goto unmap; + } + policy_file_set_mem(pf, data, size); + if (policydb_read(policydb, pf)) { + policy_file_free(pf); + policydb_free(policydb); + goto unmap; + } + if (policydb_set_vers(policydb, kernvers) || + policydb_to_image(NULL, policydb, &data, &size)) { + /* Downgrade failed, keep searching. */ + fprintf(stderr, + "SELinux: Could not downgrade policy file %s, searching for an older version.\n", + path); + policy_file_free(pf); + policydb_free(policydb); + munmap(map, sb.st_size); + close(fd); + vers--; + goto search; + } + policy_file_free(pf); + policydb_free(policydb); + } + + if (usesepol) { + if (setlocaldefs) { + void *olddata = data; + size_t oldsize = size; + rc = genusers(olddata, oldsize, selinux_users_path(), + &data, &size); + if (rc < 0) { + /* Fall back to the prior image if genusers failed. */ + data = olddata; + size = oldsize; + rc = 0; + } else { + if (olddata != map) + free(olddata); + } + } + + if (preservebools) { + int *values, len, i; + char **names; + rc = security_get_boolean_names(&names, &len); + if (!rc) { + values = malloc(sizeof(int) * len); + if (!values) { + free(names); + goto unmap; + } + for (i = 0; i < len; i++) + values[i] = + security_get_boolean_active(names[i]); + (void)genbools_array(data, size, names, values, + len); + free(values); + for (i = 0; i < len; i++) + free(names[i]); + free(names); + } + } else if (setlocaldefs) { + (void)genbools(data, size, selinux_booleans_path()); + } + } + + + rc = security_load_policy(data, size); + + if (rc) + fprintf(stderr, + "SELinux: Could not load policy file %s: %s\n", + path, strerror(errno)); + + unmap: + if (data != map) + free(data); + munmap(map, sb.st_size); + close: + close(fd); + dlclose: +#ifdef SHARED + if (errormsg) + fprintf(stderr, "libselinux: %s\n", errormsg); + if (libsepolh) + dlclose(libsepolh); +#endif + return rc; +} + +hidden_def(selinux_mkload_policy) + +/* + * Mount point for selinuxfs. + * This definition is private to the function below. + * Everything else uses the location determined during + * libselinux startup via /proc/mounts (see init_selinuxmnt). + * We only need the hardcoded definition for the initial mount + * required for the initial policy load. + */ +int selinux_init_load_policy(int *enforce) +{ + int rc = 0, orig_enforce = 0, seconfig = -2, secmdline = -1; + FILE *cfg; + char *buf; + + /* + * Reread the selinux configuration in case it has changed. + * Example: Caller has chroot'd and is now loading policy from + * chroot'd environment. + */ + selinux_reset_config(); + + /* + * Get desired mode (disabled, permissive, enforcing) from + * /etc/selinux/config. + */ + selinux_getenforcemode(&seconfig); + + /* Check for an override of the mode via the kernel command line. */ + rc = mount("proc", "/proc", "proc", 0, 0); + cfg = fopen("/proc/cmdline", "re"); + if (cfg) { + char *tmp; + buf = malloc(selinux_page_size); + if (!buf) { + fclose(cfg); + return -1; + } + if (fgets(buf, selinux_page_size, cfg) && + (tmp = strstr(buf, "enforcing="))) { + if (tmp == buf || isspace(*(tmp - 1))) { + secmdline = + atoi(tmp + sizeof("enforcing=") - 1); + } + } + fclose(cfg); + free(buf); + } + + /* + * Determine the final desired mode. + * Command line argument takes precedence, then config file. + */ + if (secmdline >= 0) + *enforce = secmdline; + else if (seconfig >= 0) + *enforce = seconfig; + else + *enforce = 0; /* unspecified or disabled */ + + /* + * Check for the existence of SELinux via selinuxfs, and + * mount it if present for use in the calls below. + */ + const char *mntpoint = NULL; + /* First make sure /sys is mounted */ + if (mount("sysfs", "/sys", "sysfs", 0, 0) == 0 || errno == EBUSY) { + if (mount(SELINUXFS, SELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = SELINUXMNT; + } else { + /* check old mountpoint */ + if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = OLDSELINUXMNT; + } + } + } else { + /* check old mountpoint */ + if (mount(SELINUXFS, OLDSELINUXMNT, SELINUXFS, 0, 0) == 0 || errno == EBUSY) { + mntpoint = OLDSELINUXMNT; + } + } + + if (! mntpoint ) { + if (errno == ENODEV || !selinuxfs_exists()) { + /* + * SELinux was disabled in the kernel, either + * omitted entirely or disabled at boot via selinux=0. + * This takes precedence over any config or + * commandline enforcing setting. + */ + *enforce = 0; + } else { + /* Only emit this error if selinux was not disabled */ + fprintf(stderr, "Mount failed for selinuxfs on %s: %s\n", SELINUXMNT, strerror(errno)); + } + + if (rc == 0) + umount2("/proc", MNT_DETACH); + + goto noload; + } + set_selinuxmnt(mntpoint); + + if (rc == 0) + umount2("/proc", MNT_DETACH); + + /* + * Note: The following code depends on having selinuxfs + * already mounted and selinuxmnt set above. + */ + + if (seconfig == -1) { + /* Runtime disable of SELinux. */ + rc = security_disable(); + if (rc == 0) { + /* Successfully disabled, so umount selinuxfs too. */ + umount(selinux_mnt); + fini_selinuxmnt(); + goto noload; + } else { + /* + * It's possible that this failed because policy has + * already been loaded. We can't disable SELinux now, + * so the best we can do is force it to be permissive. + */ + *enforce = 0; + } + } + + /* + * If necessary, change the kernel enforcing status to match + * the desired mode. + */ + orig_enforce = rc = security_getenforce(); + if (rc < 0) + goto noload; + if (orig_enforce != *enforce) { + rc = security_setenforce(*enforce); + if (rc < 0) { + fprintf(stderr, "SELinux: Unable to switch to %s mode: %s\n", (*enforce ? "enforcing" : "permissive"), strerror(errno)); + if (*enforce) + goto noload; + } + } + + if (seconfig == -1) { + umount(selinux_mnt); + fini_selinuxmnt(); + goto noload; + } + + /* Load the policy. */ + return selinux_mkload_policy(0); + + noload: + /* + * Only return 0 on a successful completion of policy load. + * In any other case, we want to return an error so that init + * knows not to proceed with the re-exec for the domain transition. + * Depending on the *enforce setting, init will halt (> 0) or proceed + * normally (otherwise). + */ + return -1; +} +#endif diff --git a/src/lsetfilecon.c b/src/lsetfilecon.c new file mode 100644 index 0000000..ea6d70b --- /dev/null +++ b/src/lsetfilecon.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +int lsetfilecon_raw(const char *path, const char * context) +{ + int rc; + if (! context) { + errno=EINVAL; + return -1; + } + + rc = lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((lgetfilecon_raw(path, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(lsetfilecon_raw) + +int lsetfilecon(const char *path, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = lsetfilecon_raw(path, rcontext); + + freecon(rcontext); + + return ret; +} diff --git a/src/mapping.c b/src/mapping.c new file mode 100644 index 0000000..33cea5a --- /dev/null +++ b/src/mapping.c @@ -0,0 +1,254 @@ +/* + * Class and permission mappings. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "mapping.h" +#include "selinux_internal.h" + +/* + * Class and permission mappings + */ + +struct selinux_mapping { + security_class_t value; /* real, kernel value */ + unsigned num_perms; + access_vector_t perms[sizeof(access_vector_t) * 8]; +}; + +static struct selinux_mapping *current_mapping = NULL; +static security_class_t current_mapping_size = 0; + +/* + * Mapping setting function + */ + +int +selinux_set_mapping(struct security_class_mapping *map) +{ + size_t size = sizeof(struct selinux_mapping); + security_class_t i, j; + unsigned k; + bool print_unknown_handle = false; + bool reject = (security_reject_unknown() == 1); + bool deny = (security_deny_unknown() == 1); + + free(current_mapping); + current_mapping = NULL; + current_mapping_size = 0; + + if (avc_reset() < 0) + goto err; + + /* Find number of classes in the input mapping */ + if (!map) { + errno = EINVAL; + goto err; + } + i = 0; + while (map[i].name) + i++; + + /* Allocate space for the class records, plus one for class zero */ + current_mapping = (struct selinux_mapping *)calloc(++i, size); + if (!current_mapping) + goto err; + + /* Store the raw class and permission values */ + j = 0; + while (map[j].name) { + struct security_class_mapping *p_in = map + (j++); + struct selinux_mapping *p_out = current_mapping + j; + + p_out->value = string_to_security_class(p_in->name); + if (!p_out->value) { + selinux_log(SELINUX_INFO, + "SELinux: Class %s not defined in policy.\n", + p_in->name); + if (reject) + goto err2; + p_out->num_perms = 0; + print_unknown_handle = true; + continue; + } + + k = 0; + while (p_in->perms[k]) { + /* An empty permission string skips ahead */ + if (!*p_in->perms[k]) { + k++; + continue; + } + p_out->perms[k] = string_to_av_perm(p_out->value, + p_in->perms[k]); + if (!p_out->perms[k]) { + selinux_log(SELINUX_INFO, + "SELinux: Permission %s in class %s not defined in policy.\n", + p_in->perms[k], p_in->name); + if (reject) + goto err2; + print_unknown_handle = true; + } + k++; + } + p_out->num_perms = k; + } + + if (print_unknown_handle) + selinux_log(SELINUX_INFO, + "SELinux: the above unknown classes and permissions will be %s\n", + deny ? "denied" : "allowed"); + + /* Set the mapping size here so the above lookups are "raw" */ + current_mapping_size = i; + return 0; +err2: + free(current_mapping); + current_mapping = NULL; + current_mapping_size = 0; +err: + return -1; +} + +/* + * Get real, kernel values from mapped values + */ + +security_class_t +unmap_class(security_class_t tclass) +{ + if (tclass < current_mapping_size) + return current_mapping[tclass].value; + + /* If here no mapping set or the class requested is not valid. */ + if (current_mapping_size != 0) { + errno = EINVAL; + return 0; + } + else + return tclass; +} + +access_vector_t +unmap_perm(security_class_t tclass, access_vector_t tperm) +{ + if (tclass < current_mapping_size) { + unsigned i; + access_vector_t kperm = 0; + + for (i=0; inum_perms; + access_vector_t result; + + for (i = 0, result = 0; i < n; i++) { + if (avd->allowed & mapping->perms[i]) + result |= 1<perms[i]) + result |= 1<allowed = result; + + for (i = 0, result = 0; i < n; i++) { + if (avd->decided & mapping->perms[i]) + result |= 1<perms[i]) + result |= 1<decided = result; + + for (i = 0, result = 0; i < n; i++) + if (avd->auditallow & mapping->perms[i]) + result |= 1<auditallow = result; + + for (i = 0, result = 0; i < n; i++) { + if (avd->auditdeny & mapping->perms[i]) + result |= 1<perms[i]) + result |= 1<num_perms since this indicates + * a bug in the object manager. + */ + for (; i < (sizeof(result)*8); i++) + result |= 1<auditdeny = result; + } +} diff --git a/src/mapping.h b/src/mapping.h new file mode 100644 index 0000000..22a4cca --- /dev/null +++ b/src/mapping.h @@ -0,0 +1,34 @@ +/* + * This file describes the class and permission mappings used to + * hide the kernel numbers from userspace by allowing userspace object + * managers to specify a list of classes and permissions. + */ +#ifndef _SELINUX_MAPPING_H_ +#define _SELINUX_MAPPING_H_ + +#include + +/* + * Get real, kernel values from mapped values + */ + +extern security_class_t +unmap_class(security_class_t tclass); + +extern access_vector_t +unmap_perm(security_class_t tclass, access_vector_t tperm); + +/* + * Get mapped values from real, kernel values + */ + +extern security_class_t +map_class(security_class_t kclass); + +extern access_vector_t +map_perm(security_class_t tclass, access_vector_t kperm); + +extern void +map_decision(security_class_t tclass, struct av_decision *avd); + +#endif /* _SELINUX_MAPPING_H_ */ diff --git a/src/matchmediacon.c b/src/matchmediacon.c new file mode 100644 index 0000000..23d01af --- /dev/null +++ b/src/matchmediacon.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include "selinux_internal.h" +#include +#include +#include +#include +#include +#include +#include + +int matchmediacon(const char *media, char ** con) +{ + const char *path = selinux_media_context_path(); + FILE *infile; + char *ptr, *ptr2 = NULL; + int found = 0; + char current_line[PATH_MAX]; + if ((infile = fopen(path, "re")) == NULL) + return -1; + while (!feof_unlocked(infile)) { + if (!fgets_unlocked(current_line, sizeof(current_line), infile)) { + return -1; + } + if (current_line[strlen(current_line) - 1]) + current_line[strlen(current_line) - 1] = 0; + /* Skip leading whitespace before the partial context. */ + ptr = current_line; + while (*ptr && isspace(*ptr)) + ptr++; + + if (!(*ptr)) + continue; + + /* Find the end of the media context. */ + ptr2 = ptr; + while (*ptr2 && !isspace(*ptr2)) + ptr2++; + if (!(*ptr2)) + continue; + + *ptr2++ = 0; + if (strcmp(media, ptr) == 0) { + found = 1; + break; + } + } + fclose(infile); + if (!found) + return -1; + + /* Skip whitespace. */ + while (*ptr2 && isspace(*ptr2)) + ptr2++; + if (!(*ptr2)) { + return -1; + } + + if (selinux_raw_to_trans_context(ptr2, con)) { + *con = NULL; + return -1; + } + + return 0; +} diff --git a/src/matchpathcon.c b/src/matchpathcon.c new file mode 100644 index 0000000..58b4144 --- /dev/null +++ b/src/matchpathcon.c @@ -0,0 +1,561 @@ +#include +#include +#include +#include +#include "selinux_internal.h" +#include "label_internal.h" +#include "callbacks.h" +#include + +static int (*myinvalidcon) (const char *p, unsigned l, char *c) = NULL; +static int (*mycanoncon) (const char *p, unsigned l, char **c) = NULL; + +static void +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))) +#endif + default_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))) +#endif + (*myprintf) (const char *fmt,...) = &default_printf; +int myprintf_compat = 0; + +void set_matchpathcon_printf(void (*f) (const char *fmt, ...)) +{ + myprintf = f ? f : &default_printf; + myprintf_compat = 1; +} + +int compat_validate(struct selabel_handle *rec, + struct selabel_lookup_rec *contexts, + const char *path, unsigned lineno) +{ + int rc; + char **ctx = &contexts->ctx_raw; + + if (myinvalidcon) + rc = myinvalidcon(path, lineno, *ctx); + else if (mycanoncon) + rc = mycanoncon(path, lineno, ctx); + else { + rc = selabel_validate(rec, contexts); + if (rc < 0) { + if (lineno) { + COMPAT_LOG(SELINUX_WARNING, + "%s: line %u has invalid context %s\n", + path, lineno, *ctx); + } else { + COMPAT_LOG(SELINUX_WARNING, + "%s: has invalid context %s\n", path, *ctx); + } + } + } + + return rc ? -1 : 0; +} + +#ifndef BUILD_HOST + +static __thread struct selabel_handle *hnd; + +/* + * An array for mapping integers to contexts + */ +static __thread char **con_array; +static __thread int con_array_size; +static __thread int con_array_used; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; + +static int add_array_elt(char *con) +{ + if (con_array_size) { + while (con_array_used >= con_array_size) { + con_array_size *= 2; + con_array = (char **)realloc(con_array, sizeof(char*) * + con_array_size); + if (!con_array) { + con_array_size = con_array_used = 0; + return -1; + } + } + } else { + con_array_size = 1000; + con_array = (char **)malloc(sizeof(char*) * con_array_size); + if (!con_array) { + con_array_size = con_array_used = 0; + return -1; + } + } + + con_array[con_array_used] = strdup(con); + if (!con_array[con_array_used]) + return -1; + return con_array_used++; +} + +static void free_array_elts(void) +{ + con_array_size = con_array_used = 0; + free(con_array); + con_array = NULL; +} + +void set_matchpathcon_invalidcon(int (*f) (const char *p, unsigned l, char *c)) +{ + myinvalidcon = f; +} + +static int default_canoncon(const char *path, unsigned lineno, char **context) +{ + char *tmpcon; + if (security_canonicalize_context_raw(*context, &tmpcon) < 0) { + if (errno == ENOENT) + return 0; + if (lineno) + myprintf("%s: line %u has invalid context %s\n", path, + lineno, *context); + else + myprintf("%s: invalid context %s\n", path, *context); + return 1; + } + free(*context); + *context = tmpcon; + return 0; +} + +void set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c)) +{ + if (f) + mycanoncon = f; + else + mycanoncon = &default_canoncon; +} + +static __thread struct selinux_opt options[SELABEL_NOPT]; +static __thread int notrans; + +void set_matchpathcon_flags(unsigned int flags) +{ + int i; + memset(options, 0, sizeof(options)); + i = SELABEL_OPT_BASEONLY; + options[i].type = i; + options[i].value = (flags & MATCHPATHCON_BASEONLY) ? (char*)1 : NULL; + i = SELABEL_OPT_VALIDATE; + options[i].type = i; + options[i].value = (flags & MATCHPATHCON_VALIDATE) ? (char*)1 : NULL; + notrans = flags & MATCHPATHCON_NOTRANS; +} + +/* + * An association between an inode and a + * specification. + */ +typedef struct file_spec { + ino_t ino; /* inode number */ + int specind; /* index of specification in spec */ + char *file; /* full pathname for diagnostic messages about conflicts */ + struct file_spec *next; /* next association in hash bucket chain */ +} file_spec_t; + +/* + * The hash table of associations, hashed by inode number. + * Chaining is used for collisions, with elements ordered + * by inode number in each bucket. Each hash bucket has a dummy + * header. + */ +#define HASH_BITS 16 +#define HASH_BUCKETS (1 << HASH_BITS) +#define HASH_MASK (HASH_BUCKETS-1) +static file_spec_t *fl_head; + +/* + * Try to add an association between an inode and + * a specification. If there is already an association + * for the inode and it conflicts with this specification, + * then use the specification that occurs later in the + * specification array. + */ +int matchpathcon_filespec_add(ino_t ino, int specind, const char *file) +{ + file_spec_t *prevfl, *fl; + int h, ret; + struct stat sb; + + if (!fl_head) { + fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + if (!fl_head) + goto oom; + memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); + } + + h = (ino + (ino >> HASH_BITS)) & HASH_MASK; + for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; + prevfl = fl, fl = fl->next) { + if (ino == fl->ino) { + ret = lstat(fl->file, &sb); + if (ret < 0 || sb.st_ino != ino) { + fl->specind = specind; + free(fl->file); + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom; + strcpy(fl->file, file); + return fl->specind; + + } + + if (!strcmp(con_array[fl->specind], + con_array[specind])) + return fl->specind; + + myprintf + ("%s: conflicting specifications for %s and %s, using %s.\n", + __FUNCTION__, file, fl->file, + con_array[fl->specind]); + free(fl->file); + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom; + strcpy(fl->file, file); + return fl->specind; + } + + if (ino > fl->ino) + break; + } + + fl = malloc(sizeof(file_spec_t)); + if (!fl) + goto oom; + fl->ino = ino; + fl->specind = specind; + fl->file = malloc(strlen(file) + 1); + if (!fl->file) + goto oom_freefl; + strcpy(fl->file, file); + fl->next = prevfl->next; + prevfl->next = fl; + return fl->specind; + oom_freefl: + free(fl); + oom: + myprintf("%s: insufficient memory for file label entry for %s\n", + __FUNCTION__, file); + return -1; +} + +/* + * Evaluate the association hash table distribution. + */ +void matchpathcon_filespec_eval(void) +{ + file_spec_t *fl; + int h, used, nel, len, longest; + + if (!fl_head) + return; + + used = 0; + longest = 0; + nel = 0; + for (h = 0; h < HASH_BUCKETS; h++) { + len = 0; + for (fl = fl_head[h].next; fl; fl = fl->next) { + len++; + } + if (len) + used++; + if (len > longest) + longest = len; + nel += len; + } + + myprintf + ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", + __FUNCTION__, nel, used, HASH_BUCKETS, longest); +} + +/* + * Destroy the association hash table. + */ +void matchpathcon_filespec_destroy(void) +{ + file_spec_t *fl, *tmp; + int h; + + free_array_elts(); + + if (!fl_head) + return; + + for (h = 0; h < HASH_BUCKETS; h++) { + fl = fl_head[h].next; + while (fl) { + tmp = fl; + fl = fl->next; + free(tmp->file); + free(tmp); + } + fl_head[h].next = NULL; + } + free(fl_head); + fl_head = NULL; +} + +static void matchpathcon_thread_destructor(void __attribute__((unused)) *ptr) +{ + matchpathcon_fini(); +} + +void __attribute__((destructor)) matchpathcon_lib_destructor(void); + +void hidden __attribute__((destructor)) matchpathcon_lib_destructor(void) +{ + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static void matchpathcon_init_once(void) +{ + if (__selinux_key_create(&destructor_key, matchpathcon_thread_destructor) == 0) + destructor_key_initialized = 1; +} + +int matchpathcon_init_prefix(const char *path, const char *subset) +{ + if (!mycanoncon) + mycanoncon = default_canoncon; + + __selinux_once(once, matchpathcon_init_once); + __selinux_setspecific(destructor_key, (void *)1); + + options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; + options[SELABEL_OPT_SUBSET].value = subset; + options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH; + options[SELABEL_OPT_PATH].value = path; + + hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT); + return hnd ? 0 : -1; +} + +hidden_def(matchpathcon_init_prefix) + +int matchpathcon_init(const char *path) +{ + return matchpathcon_init_prefix(path, NULL); +} + +void matchpathcon_fini(void) +{ + free_array_elts(); + + if (hnd) { + selabel_close(hnd); + hnd = NULL; + } +} + +/* + * We do not want to resolve a symlink to a real path if it is the final + * component of the name. Thus we split the pathname on the last "/" and + * determine a real path component of the first portion. We then have to + * copy the last part back on to get the final real path. Wheww. + */ +int realpath_not_final(const char *name, char *resolved_path) +{ + char *last_component; + char *tmp_path, *p; + size_t len = 0; + int rc = 0; + + tmp_path = strdup(name); + if (!tmp_path) { + myprintf("symlink_realpath(%s) strdup() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + last_component = strrchr(tmp_path, '/'); + + if (last_component == tmp_path) { + last_component++; + p = strcpy(resolved_path, ""); + } else if (last_component) { + *last_component = '\0'; + last_component++; + p = realpath(tmp_path, resolved_path); + } else { + last_component = tmp_path; + p = realpath("./", resolved_path); + } + + if (!p) { + myprintf("symlink_realpath(%s) realpath() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + len = strlen(p); + if (len + strlen(last_component) + 2 > PATH_MAX) { + myprintf("symlink_realpath(%s) failed: Filename too long \n", + name); + errno=ENAMETOOLONG; + rc = -1; + goto out; + } + + resolved_path += len; + strcpy(resolved_path, "/"); + resolved_path += 1; + strcpy(resolved_path, last_component); +out: + free(tmp_path); + return rc; +} + +int matchpathcon(const char *path, mode_t mode, char ** con) +{ + char stackpath[PATH_MAX + 1]; + char *p = NULL; + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + if (S_ISLNK(mode)) { + if (!realpath_not_final(path, stackpath)) + path = stackpath; + } else { + p = realpath(path, stackpath); + if (p) + path = p; + } + + return notrans ? + selabel_lookup_raw(hnd, con, path, mode) : + selabel_lookup(hnd, con, path, mode); +} + +int matchpathcon_index(const char *name, mode_t mode, char ** con) +{ + int i = matchpathcon(name, mode, con); + + if (i < 0) + return -1; + + return add_array_elt(*con); +} + +void matchpathcon_checkmatches(char *str __attribute__((unused))) +{ + selabel_stats(hnd); +} + +/* Compare two contexts to see if their differences are "significant", + * or whether the only difference is in the user. */ +int selinux_file_context_cmp(const char * a, + const char * b) +{ + char *rest_a, *rest_b; /* Rest of the context after the user */ + if (!a && !b) + return 0; + if (!a) + return -1; + if (!b) + return 1; + rest_a = strchr((char *)a, ':'); + rest_b = strchr((char *)b, ':'); + if (!rest_a && !rest_b) + return 0; + if (!rest_a) + return -1; + if (!rest_b) + return 1; + return strcmp(rest_a, rest_b); +} + +int selinux_file_context_verify(const char *path, mode_t mode) +{ + char * con = NULL; + char * fcontext = NULL; + int rc = 0; + char stackpath[PATH_MAX + 1]; + char *p = NULL; + + if (S_ISLNK(mode)) { + if (!realpath_not_final(path, stackpath)) + path = stackpath; + } else { + p = realpath(path, stackpath); + if (p) + path = p; + } + + rc = lgetfilecon_raw(path, &con); + if (rc == -1) { + if (errno != ENOTSUP) + return -1; + else + return 0; + } + + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) { + if (errno != ENOENT) + rc = -1; + else + rc = 0; + } else { + /* + * Need to set errno to 0 as it can be set to ENOENT if the + * file_contexts.subs file does not exist (see selabel_open in + * label.c), thus causing confusion if errno is checked on return. + */ + errno = 0; + rc = (selinux_file_context_cmp(fcontext, con) == 0); + } + + freecon(con); + freecon(fcontext); + return rc; +} + +int selinux_lsetfilecon_default(const char *path) +{ + struct stat st; + int rc = -1; + char * scontext = NULL; + if (lstat(path, &st) != 0) + return rc; + + if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) + return -1; + + /* If there's an error determining the context, or it has none, + return to allow default context */ + if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) { + if (errno == ENOENT) + rc = 0; + } else { + rc = lsetfilecon_raw(path, scontext); + freecon(scontext); + } + return rc; +} + +#endif diff --git a/src/policy.h b/src/policy.h new file mode 100644 index 0000000..f6d7242 --- /dev/null +++ b/src/policy.h @@ -0,0 +1,34 @@ +#ifndef _POLICY_H_ +#define _POLICY_H_ + +/* Private definitions used internally by libselinux. */ + +/* + * xattr name for SELinux attributes. + * This may have been exported via Kernel uapi header. + */ +#ifndef XATTR_NAME_SELINUX +#define XATTR_NAME_SELINUX "security.selinux" +#endif + +/* Initial length guess for getting contexts. */ +#define INITCONTEXTLEN 255 + +/* selinux file system type */ +#define SELINUXFS "selinuxfs" + +/* selinuxfs magic number */ +#define SELINUX_MAGIC 0xf97cff8c + +/* Preferred selinux mount location */ +#define SELINUXMNT "/sys/fs/selinux" +#define OLDSELINUXMNT "/selinux" + +/* selinuxfs mount point */ +extern char *selinux_mnt; + +#define FILECONTEXTS "/etc/security/selinux/file_contexts" + +#define DEFAULT_POLICY_VERSION 15 + +#endif diff --git a/src/policyvers.c b/src/policyvers.c new file mode 100644 index 0000000..c97dd9d --- /dev/null +++ b/src/policyvers.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include +#include "policy.h" +#include "dso.h" +#include + +int security_policyvers(void) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + unsigned vers = DEFAULT_POLICY_VERSION; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/policyvers", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + if (errno == ENOENT) + return vers; + else + return -1; + } + memset(buf, 0, sizeof buf); + ret = read(fd, buf, sizeof buf - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%u", &vers) != 1) + return -1; + + return vers; +} + +hidden_def(security_policyvers) diff --git a/src/procattr.c b/src/procattr.c new file mode 100644 index 0000000..cbb6824 --- /dev/null +++ b/src/procattr.c @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +#define UNSET (char *) -1 + +static __thread char *prev_current = UNSET; +static __thread char * prev_exec = UNSET; +static __thread char * prev_fscreate = UNSET; +static __thread char * prev_keycreate = UNSET; +static __thread char * prev_sockcreate = UNSET; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; +static __thread char destructor_initialized; + +/* Bionic and glibc >= 2.30 declare gettid() system call wrapper in unistd.h and + * has a definition for it */ +#ifndef OVERRIDE_GETTID +#ifdef __BIONIC__ + #define OVERRIDE_GETTID 0 +#elif !defined(__GLIBC_PREREQ) + #define OVERRIDE_GETTID 1 +#elif !__GLIBC_PREREQ(2,30) + #define OVERRIDE_GETTID 1 +#else + #define OVERRIDE_GETTID 0 +#endif +#endif + +#if OVERRIDE_GETTID +static pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#endif + +static void procattr_thread_destructor(void __attribute__((unused)) *unused) +{ + if (prev_current != UNSET) + free(prev_current); + if (prev_exec != UNSET) + free(prev_exec); + if (prev_fscreate != UNSET) + free(prev_fscreate); + if (prev_keycreate != UNSET) + free(prev_keycreate); + if (prev_sockcreate != UNSET) + free(prev_sockcreate); +} + +void __attribute__((destructor)) procattr_destructor(void); + +void hidden __attribute__((destructor)) procattr_destructor(void) +{ + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static inline void init_thread_destructor(void) +{ + if (destructor_initialized == 0) { + __selinux_setspecific(destructor_key, (void *)1); + destructor_initialized = 1; + } +} + +static void init_procattr(void) +{ + if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) { + destructor_key_initialized = 1; + } +} + +static int openattr(pid_t pid, const char *attr, int flags) +{ + int fd, rc; + char *path; + pid_t tid; + + if (pid > 0) { + rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); + } else if (pid == 0) { + rc = asprintf(&path, "/proc/thread-self/attr/%s", attr); + if (rc < 0) + return -1; + fd = open(path, flags | O_CLOEXEC); + if (fd >= 0 || errno != ENOENT) + goto out; + free(path); + tid = gettid(); + rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); + } else { + errno = EINVAL; + return -1; + } + if (rc < 0) + return -1; + + fd = open(path, flags | O_CLOEXEC); +out: + free(path); + return fd; +} + +static int getprocattrcon_raw(char ** context, + pid_t pid, const char *attr) +{ + char *buf; + size_t size; + int fd; + ssize_t ret; + int errno_hold; + char * prev_context; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + + switch (attr[0]) { + case 'c': + prev_context = prev_current; + break; + case 'e': + prev_context = prev_exec; + break; + case 'f': + prev_context = prev_fscreate; + break; + case 'k': + prev_context = prev_keycreate; + break; + case 's': + prev_context = prev_sockcreate; + break; + case 'p': + prev_context = NULL; + break; + default: + errno = ENOENT; + return -1; + }; + + if (prev_context && prev_context != UNSET) { + *context = strdup(prev_context); + if (!(*context)) { + return -1; + } + return 0; + } + + fd = openattr(pid, attr, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + size = selinux_page_size; + buf = malloc(size); + if (!buf) { + ret = -1; + goto out; + } + memset(buf, 0, size); + + do { + ret = read(fd, buf, size - 1); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + goto out2; + + if (ret == 0) { + *context = NULL; + goto out2; + } + + *context = strdup(buf); + if (!(*context)) { + ret = -1; + goto out2; + } + ret = 0; + out2: + free(buf); + out: + errno_hold = errno; + close(fd); + errno = errno_hold; + return ret; +} + +static int getprocattrcon(char ** context, + pid_t pid, const char *attr) +{ + int ret; + char * rcontext; + + ret = getprocattrcon_raw(&rcontext, pid, attr); + + if (!ret) { + ret = selinux_raw_to_trans_context(rcontext, context); + freecon(rcontext); + } + + return ret; +} + +static int setprocattrcon_raw(const char * context, + pid_t pid, const char *attr) +{ + int fd; + ssize_t ret; + int errno_hold; + char **prev_context, *context2 = NULL; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + + switch (attr[0]) { + case 'c': + prev_context = &prev_current; + break; + case 'e': + prev_context = &prev_exec; + break; + case 'f': + prev_context = &prev_fscreate; + break; + case 'k': + prev_context = &prev_keycreate; + break; + case 's': + prev_context = &prev_sockcreate; + break; + default: + errno = ENOENT; + return -1; + }; + + if (!context && !*prev_context) + return 0; + if (context && *prev_context && *prev_context != UNSET + && !strcmp(context, *prev_context)) + return 0; + + fd = openattr(pid, attr, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + if (context) { + ret = -1; + context2 = strdup(context); + if (!context2) + goto out; + do { + ret = write(fd, context2, strlen(context2) + 1); + } while (ret < 0 && errno == EINTR); + } else { + do { + ret = write(fd, NULL, 0); /* clear */ + } while (ret < 0 && errno == EINTR); + } +out: + errno_hold = errno; + close(fd); + errno = errno_hold; + if (ret < 0) { + free(context2); + return -1; + } else { + if (*prev_context != UNSET) + free(*prev_context); + *prev_context = context2; + return 0; + } +} + +static int setprocattrcon(const char * context, + pid_t pid, const char *attr) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = setprocattrcon_raw(rcontext, pid, attr); + + freecon(rcontext); + + return ret; +} + +#define getselfattr_def(fn, attr) \ + int get##fn##_raw(char **c) \ + { \ + return getprocattrcon_raw(c, 0, #attr); \ + } \ + int get##fn(char **c) \ + { \ + return getprocattrcon(c, 0, #attr); \ + } + +#define setselfattr_def(fn, attr) \ + int set##fn##_raw(const char * c) \ + { \ + return setprocattrcon_raw(c, 0, #attr); \ + } \ + int set##fn(const char * c) \ + { \ + return setprocattrcon(c, 0, #attr); \ + } + +#define all_selfattr_def(fn, attr) \ + getselfattr_def(fn, attr) \ + setselfattr_def(fn, attr) + +#define getpidattr_def(fn, attr) \ + int get##fn##_raw(pid_t pid, char **c) \ + { \ + if (pid <= 0) { \ + errno = EINVAL; \ + return -1; \ + } else { \ + return getprocattrcon_raw(c, pid, #attr); \ + } \ + } \ + int get##fn(pid_t pid, char **c) \ + { \ + if (pid <= 0) { \ + errno = EINVAL; \ + return -1; \ + } else { \ + return getprocattrcon(c, pid, #attr); \ + } \ + } + +all_selfattr_def(con, current) + getpidattr_def(pidcon, current) + getselfattr_def(prevcon, prev) + all_selfattr_def(execcon, exec) + all_selfattr_def(fscreatecon, fscreate) + all_selfattr_def(sockcreatecon, sockcreate) + all_selfattr_def(keycreatecon, keycreate) + + hidden_def(getcon_raw) + hidden_def(getcon) + hidden_def(getexeccon_raw) + hidden_def(getfilecon_raw) + hidden_def(getfilecon) + hidden_def(getfscreatecon_raw) + hidden_def(getkeycreatecon_raw) + hidden_def(getpeercon_raw) + hidden_def(getpidcon_raw) + hidden_def(getprevcon_raw) + hidden_def(getprevcon) + hidden_def(getsockcreatecon_raw) + hidden_def(setcon_raw) + hidden_def(setexeccon_raw) + hidden_def(setexeccon) + hidden_def(setfilecon_raw) + hidden_def(setfscreatecon_raw) + hidden_def(setkeycreatecon_raw) + hidden_def(setsockcreatecon_raw) diff --git a/src/query_user_context.c b/src/query_user_context.c new file mode 100644 index 0000000..b8125c9 --- /dev/null +++ b/src/query_user_context.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include "selinux_internal.h" +#include "context_internal.h" +#include + +/* context_menu - given a list of contexts, presents a menu of security contexts + * to the user. Returns the number (position in the list) of + * the user selected context. + */ +static int context_menu(char ** list) +{ + int i; /* array index */ + int choice = 0; /* index of the user's choice */ + char response[10]; /* string to hold the user's response */ + + printf("\n\n"); + for (i = 0; list[i]; i++) + printf("[%d] %s\n", i + 1, list[i]); + + while ((choice < 1) || (choice > i)) { + printf("Enter number of choice: "); + fflush(stdin); + if (fgets(response, sizeof(response), stdin) == NULL) + continue; + fflush(stdin); + choice = strtol(response, NULL, 10); + } + + return (choice - 1); +} + +/* query_user_context - given a list of context, allow the user to choose one. The + * default is the first context in the list. Returns 0 on + * success, -1 on failure + */ +int query_user_context(char ** list, char ** usercon) +{ + char response[10]; /* The user's response */ + int choice; /* The index in the list of the sid chosen by + the user */ + + if (!list[0]) + return -1; + + printf("\nYour default context is %s.\n", list[0]); + if (list[1]) { + printf("Do you want to choose a different one? [n]"); + fflush(stdin); + if (fgets(response, sizeof(response), stdin) == NULL) + return -1; + fflush(stdin); + + if ((response[0] == 'y') || (response[0] == 'Y')) { + choice = context_menu(list); + *usercon = strdup(list[choice]); + if (!(*usercon)) + return -1; + return 0; + } + + *usercon = strdup(list[0]); + if (!(*usercon)) + return -1; + } else { + *usercon = strdup(list[0]); + if (!(*usercon)) + return -1; + } + + return 0; +} + +/* get_field - given fieldstr - the "name" of a field, query the user + * and set the new value of the field + */ +static void get_field(const char *fieldstr, char *newfield, int newfieldlen) +{ + int done = 0; /* true if a non-empty field has been obtained */ + + while (!done) { /* Keep going until we get a value for the field */ + printf("\tEnter %s ", fieldstr); + fflush(stdin); + if (fgets(newfield, newfieldlen, stdin) == NULL) + continue; + fflush(stdin); + if (newfield[strlen(newfield) - 1] == '\n') + newfield[strlen(newfield) - 1] = '\0'; + + if (strlen(newfield) == 0) { + printf("You must enter a %s\n", fieldstr); + } else { + done = 1; + } + } +} + +/* manual_user_enter_context - provides a way for a user to manually enter a + * context in case the policy doesn't allow a list + * to be obtained. + * given the userid, queries the user and places the + * context chosen by the user into usercon. Returns 0 + * on success. + */ +int manual_user_enter_context(const char *user, char ** newcon) +{ + char response[10]; /* Used to get yes or no answers from user */ + char role[100]; /* The role requested by the user */ + int rolelen = 100; + char type[100]; /* The type requested by the user */ + int typelen = 100; + char level[100]; /* The level requested by the user */ + int levellen = 100; + int mls_enabled = is_selinux_mls_enabled(); + + context_t new_context; /* The new context chosen by the user */ + char *user_context = NULL; /* String value of the user's context */ + int done = 0; /* true if a valid sid has been obtained */ + + /* Initialize the context. How this is done depends on whether + or not MLS is enabled */ + if (mls_enabled) + new_context = context_new("user:role:type:level"); + else + new_context = context_new("user:role:type"); + + if (!new_context) + return -1; + + while (!done) { + printf("Would you like to enter a security context? [y]"); + if (fgets(response, sizeof(response), stdin) == NULL + || (response[0] == 'n') || (response[0] == 'N')) { + context_free(new_context); + return -1; + } + + /* Allow the user to enter each field of the context individually */ + if (context_user_set(new_context, user)) { + context_free(new_context); + return -1; + } + get_field("role", role, rolelen); + if (context_role_set(new_context, role)) { + context_free(new_context); + return -1; + } + get_field("type", type, typelen); + if (context_type_set(new_context, type)) { + context_free(new_context); + return -1; + } + + if (mls_enabled) { + get_field("level", level, levellen); + if (context_range_set(new_context, level)) { + context_free(new_context); + return -1; + } + } + + /* Get the string value of the context and see if it is valid. */ + user_context = context_str(new_context); + if (!user_context) { + context_free(new_context); + return -1; + } + if (!security_check_context(user_context)) + done = 1; + else + printf("Not a valid security context\n"); + } + + *newcon = strdup(user_context); + context_free(new_context); + if (!(*newcon)) + return -1; + return 0; +} diff --git a/src/regex.c b/src/regex.c new file mode 100644 index 0000000..a6fcbbf --- /dev/null +++ b/src/regex.c @@ -0,0 +1,575 @@ +#include +#include +#include +#include +#include + +#include "regex.h" +#include "label_file.h" +#include "selinux_internal.h" + +#ifdef USE_PCRE2 +#define REGEX_ARCH_SIZE_T PCRE2_SIZE +#else +#define REGEX_ARCH_SIZE_T size_t +#endif + +#ifndef __BYTE_ORDER__ + +/* If the compiler doesn't define __BYTE_ORDER__, try to use the C + * library header definitions. */ +#include +#ifndef __BYTE_ORDER +#error Neither __BYTE_ORDER__ nor __BYTE_ORDER defined. Unable to determine endianness. +#endif + +#define __ORDER_LITTLE_ENDIAN __LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN __BIG_ENDIAN +#define __BYTE_ORDER__ __BYTE_ORDER + +#endif + +#ifdef USE_PCRE2 +char const *regex_arch_string(void) +{ + static char arch_string_buffer[32]; + static char const *arch_string = ""; + char const *endianness = NULL; + int rc; + + if (arch_string[0] == '\0') { + if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + endianness = "el"; + else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + endianness = "eb"; + + if (!endianness) + return NULL; + + rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer), + "%zu-%zu-%s", sizeof(void *), + sizeof(REGEX_ARCH_SIZE_T), + endianness); + if (rc < 0) + abort(); + + arch_string = &arch_string_buffer[0]; + } + return arch_string; +} + +struct regex_data { + pcre2_code *regex; /* compiled regular expression */ + /* + * match data block required for the compiled + * pattern in pcre2 + */ + pcre2_match_data *match_data; + pthread_mutex_t match_mutex; +}; + +int regex_prepare_data(struct regex_data **regex, char const *pattern_string, + struct regex_error_data *errordata) +{ + memset(errordata, 0, sizeof(struct regex_error_data)); + + *regex = regex_data_create(); + if (!(*regex)) + return -1; + + (*regex)->regex = pcre2_compile( + (PCRE2_SPTR)pattern_string, PCRE2_ZERO_TERMINATED, PCRE2_DOTALL, + &errordata->error_code, &errordata->error_offset, NULL); + if (!(*regex)->regex) { + goto err; + } + + (*regex)->match_data = + pcre2_match_data_create_from_pattern((*regex)->regex, NULL); + if (!(*regex)->match_data) { + goto err; + } + return 0; + +err: + regex_data_free(*regex); + *regex = NULL; + return -1; +} + +char const *regex_version(void) +{ + static char version_buf[256]; + size_t len = pcre2_config(PCRE2_CONFIG_VERSION, NULL); + if (len <= 0 || len > sizeof(version_buf)) + return NULL; + + pcre2_config(PCRE2_CONFIG_VERSION, version_buf); + return version_buf; +} + +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex, + int do_load_precompregex, bool *regex_compiled) +{ + int rc; + uint32_t entry_len; + + *regex_compiled = false; + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0) + return -1; + + if (entry_len && do_load_precompregex) { + /* + * this should yield exactly one because we store one pattern at + * a time + */ + rc = pcre2_serialize_get_number_of_codes(mmap_area->next_addr); + if (rc != 1) + return -1; + + *regex = regex_data_create(); + if (!*regex) + return -1; + + rc = pcre2_serialize_decode(&(*regex)->regex, 1, + (PCRE2_SPTR)mmap_area->next_addr, + NULL); + if (rc != 1) + goto err; + + (*regex)->match_data = + pcre2_match_data_create_from_pattern((*regex)->regex, NULL); + if (!(*regex)->match_data) + goto err; + + *regex_compiled = true; + } + + /* and skip the decoded bit */ + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + return 0; +err: + regex_data_free(*regex); + *regex = NULL; + return -1; +} + +int regex_writef(struct regex_data *regex, FILE *fp, int do_write_precompregex) +{ + int rc = 0; + size_t len; + PCRE2_SIZE serialized_size; + uint32_t to_write = 0; + PCRE2_UCHAR *bytes = NULL; + + if (do_write_precompregex) { + /* encode the patter for serialization */ + rc = pcre2_serialize_encode((const pcre2_code **)®ex->regex, + 1, &bytes, &serialized_size, NULL); + if (rc != 1) { + rc = -1; + goto out; + } + to_write = serialized_size; + } + + /* write serialized pattern's size */ + len = fwrite(&to_write, sizeof(uint32_t), 1, fp); + if (len != 1) { + rc = -1; + goto out; + } + + if (do_write_precompregex) { + /* write serialized pattern */ + len = fwrite(bytes, 1, to_write, fp); + if (len != to_write) + rc = -1; + } + +out: + if (bytes) + pcre2_serialize_free(bytes); + + return rc; +} + +void regex_data_free(struct regex_data *regex) +{ + if (regex) { + if (regex->regex) + pcre2_code_free(regex->regex); + if (regex->match_data) + pcre2_match_data_free(regex->match_data); + __pthread_mutex_destroy(®ex->match_mutex); + free(regex); + } +} + +int regex_match(struct regex_data *regex, char const *subject, int partial) +{ + int rc; + __pthread_mutex_lock(®ex->match_mutex); + rc = pcre2_match( + regex->regex, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0, + partial ? PCRE2_PARTIAL_SOFT : 0, regex->match_data, NULL); + __pthread_mutex_unlock(®ex->match_mutex); + if (rc > 0) + return REGEX_MATCH; + switch (rc) { + case PCRE2_ERROR_PARTIAL: + return REGEX_MATCH_PARTIAL; + case PCRE2_ERROR_NOMATCH: + return REGEX_NO_MATCH; + default: + return REGEX_ERROR; + } +} + +/* + * TODO Replace this compare function with something that actually compares the + * regular expressions. + * This compare function basically just compares the binary representations of + * the automatons, and because this representation contains pointers and + * metadata, it can only return a match if regex1 == regex2. + * Preferably, this function would be replaced with an algorithm that computes + * the equivalence of the automatons systematically. + */ +int regex_cmp(struct regex_data *regex1, struct regex_data *regex2) +{ + int rc; + size_t len1, len2; + rc = pcre2_pattern_info(regex1->regex, PCRE2_INFO_SIZE, &len1); + assert(rc == 0); + rc = pcre2_pattern_info(regex2->regex, PCRE2_INFO_SIZE, &len2); + assert(rc == 0); + if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1)) + return SELABEL_INCOMPARABLE; + + return SELABEL_EQUAL; +} + +struct regex_data *regex_data_create(void) +{ + struct regex_data *regex_data = + (struct regex_data *)calloc(1, sizeof(struct regex_data)); + __pthread_mutex_init(®ex_data->match_mutex, NULL); + return regex_data; +} + +#else // !USE_PCRE2 +char const *regex_arch_string(void) +{ + return "N/A"; +} + +/* Prior to version 8.20, libpcre did not have pcre_free_study() */ +#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20)) +#define pcre_free_study pcre_free +#endif + +struct regex_data { + int owned; /* + * non zero if regex and pcre_extra is owned by this + * structure and thus must be freed on destruction. + */ + pcre *regex; /* compiled regular expression */ + union { + pcre_extra *sd; /* pointer to extra compiled stuff */ + pcre_extra lsd; /* used to hold the mmap'd version */ + }; +}; + +int regex_prepare_data(struct regex_data **regex, char const *pattern_string, + struct regex_error_data *errordata) +{ + memset(errordata, 0, sizeof(struct regex_error_data)); + + *regex = regex_data_create(); + if (!(*regex)) + return -1; + + (*regex)->regex = + pcre_compile(pattern_string, PCRE_DOTALL, &errordata->error_buffer, + &errordata->error_offset, NULL); + if (!(*regex)->regex) + goto err; + + (*regex)->owned = 1; + + (*regex)->sd = pcre_study((*regex)->regex, 0, &errordata->error_buffer); + if (!(*regex)->sd && errordata->error_buffer) + goto err; + + return 0; + +err: + regex_data_free(*regex); + *regex = NULL; + return -1; +} + +char const *regex_version(void) +{ + return pcre_version(); +} + +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex, + int unused __attribute__((unused)), bool *regex_compiled) +{ + int rc; + uint32_t entry_len; + size_t info_len; + + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0 || !entry_len) + return -1; + + *regex = regex_data_create(); + if (!(*regex)) + return -1; + + (*regex)->owned = 0; + (*regex)->regex = (pcre *)mmap_area->next_addr; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + /* + * Check that regex lengths match. pcre_fullinfo() + * also validates its magic number. + */ + rc = pcre_fullinfo((*regex)->regex, NULL, PCRE_INFO_SIZE, &info_len); + if (rc < 0 || info_len != entry_len) + goto err; + + rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); + if (rc < 0) + goto err; + + if (entry_len) { + (*regex)->lsd.study_data = (void *)mmap_area->next_addr; + (*regex)->lsd.flags |= PCRE_EXTRA_STUDY_DATA; + rc = next_entry(NULL, mmap_area, entry_len); + if (rc < 0) + goto err; + + /* Check that study data lengths match. */ + rc = pcre_fullinfo((*regex)->regex, &(*regex)->lsd, + PCRE_INFO_STUDYSIZE, &info_len); + if (rc < 0 || info_len != entry_len) + goto err; + } + + *regex_compiled = true; + return 0; + +err: + regex_data_free(*regex); + *regex = NULL; + return -1; +} + +static inline pcre_extra *get_pcre_extra(struct regex_data *regex) +{ + if (!regex) return NULL; + if (regex->owned) { + return regex->sd; + } else if (regex->lsd.study_data) { + return ®ex->lsd; + } else { + return NULL; + } +} + +int regex_writef(struct regex_data *regex, FILE *fp, + int unused __attribute__((unused))) +{ + int rc; + size_t len; + uint32_t to_write; + size_t size; + pcre_extra *sd = get_pcre_extra(regex); + + /* determine the size of the pcre data in bytes */ + rc = pcre_fullinfo(regex->regex, NULL, PCRE_INFO_SIZE, &size); + if (rc < 0) + return -1; + + /* write the number of bytes in the pcre data */ + to_write = size; + len = fwrite(&to_write, sizeof(uint32_t), 1, fp); + if (len != 1) + return -1; + + /* write the actual pcre data as a char array */ + len = fwrite(regex->regex, 1, to_write, fp); + if (len != to_write) + return -1; + + if (sd) { + /* determine the size of the pcre study info */ + rc = + pcre_fullinfo(regex->regex, sd, PCRE_INFO_STUDYSIZE, &size); + if (rc < 0) + return -1; + } else + size = 0; + + /* write the number of bytes in the pcre study data */ + to_write = size; + len = fwrite(&to_write, sizeof(uint32_t), 1, fp); + if (len != 1) + return -1; + + if (sd) { + /* write the actual pcre study data as a char array */ + len = fwrite(sd->study_data, 1, to_write, fp); + if (len != to_write) + return -1; + } + + return 0; +} + +void regex_data_free(struct regex_data *regex) +{ + if (regex) { + if (regex->owned) { + if (regex->regex) + pcre_free(regex->regex); + if (regex->sd) + pcre_free_study(regex->sd); + } + free(regex); + } +} + +int regex_match(struct regex_data *regex, char const *subject, int partial) +{ + int rc; + + rc = pcre_exec(regex->regex, get_pcre_extra(regex), + subject, strlen(subject), 0, + partial ? PCRE_PARTIAL_SOFT : 0, NULL, 0); + switch (rc) { + case 0: + return REGEX_MATCH; + case PCRE_ERROR_PARTIAL: + return REGEX_MATCH_PARTIAL; + case PCRE_ERROR_NOMATCH: + return REGEX_NO_MATCH; + default: + return REGEX_ERROR; + } +} + +/* + * TODO Replace this compare function with something that actually compares the + * regular expressions. + * This compare function basically just compares the binary representations of + * the automatons, and because this representation contains pointers and + * metadata, it can only return a match if regex1 == regex2. + * Preferably, this function would be replaced with an algorithm that computes + * the equivalence of the automatons systematically. + */ +int regex_cmp(struct regex_data *regex1, struct regex_data *regex2) +{ + int rc; + size_t len1, len2; + rc = pcre_fullinfo(regex1->regex, NULL, PCRE_INFO_SIZE, &len1); + assert(rc == 0); + rc = pcre_fullinfo(regex2->regex, NULL, PCRE_INFO_SIZE, &len2); + assert(rc == 0); + if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1)) + return SELABEL_INCOMPARABLE; + + return SELABEL_EQUAL; +} + +struct regex_data *regex_data_create(void) +{ + return (struct regex_data *)calloc(1, sizeof(struct regex_data)); +} + +#endif + +void regex_format_error(struct regex_error_data const *error_data, char *buffer, + size_t buf_size) +{ + unsigned the_end_length = buf_size > 4 ? 4 : buf_size; + char *ptr = &buffer[buf_size - the_end_length]; + int rc = 0; + size_t pos = 0; + if (!buffer || !buf_size) + return; + rc = snprintf(buffer, buf_size, "REGEX back-end error: "); + if (rc < 0) + /* + * If snprintf fails it constitutes a logical error that needs + * fixing. + */ + abort(); + + pos += rc; + if (pos >= buf_size) + goto truncated; + + if (error_data->error_offset > 0) { +#ifdef USE_PCRE2 + rc = snprintf(buffer + pos, buf_size - pos, "At offset %zu: ", + error_data->error_offset); +#else + rc = snprintf(buffer + pos, buf_size - pos, "At offset %d: ", + error_data->error_offset); +#endif + if (rc < 0) + abort(); + } + pos += rc; + if (pos >= buf_size) + goto truncated; + +#ifdef USE_PCRE2 + rc = pcre2_get_error_message(error_data->error_code, + (PCRE2_UCHAR *)(buffer + pos), + buf_size - pos); + if (rc == PCRE2_ERROR_NOMEMORY) + goto truncated; +#else + rc = snprintf(buffer + pos, buf_size - pos, "%s", + error_data->error_buffer); + if (rc < 0) + abort(); + + if ((size_t)rc < strlen(error_data->error_buffer)) + goto truncated; +#endif + + return; + +truncated: + /* replace end of string with "..." to indicate that it was truncated */ + switch (the_end_length) { + /* no break statements, fall-through is intended */ + case 4: + *ptr++ = '.'; + /* FALLTHRU */ + case 3: + *ptr++ = '.'; + /* FALLTHRU */ + case 2: + *ptr++ = '.'; + /* FALLTHRU */ + case 1: + *ptr++ = '\0'; + /* FALLTHRU */ + default: + break; + } + return; +} diff --git a/src/regex.h b/src/regex.h new file mode 100644 index 0000000..eb8ca50 --- /dev/null +++ b/src/regex.h @@ -0,0 +1,167 @@ +#ifndef SRC_REGEX_H_ +#define SRC_REGEX_H_ + +#include +#include + +#ifdef USE_PCRE2 +#include +#else +#include +#endif + +#include "dso.h" + +enum { REGEX_MATCH, + REGEX_MATCH_PARTIAL, + REGEX_NO_MATCH, + REGEX_ERROR = -1, +}; + +struct regex_data; + +#ifdef USE_PCRE2 +struct regex_error_data { + int error_code; + PCRE2_SIZE error_offset; +}; +#else +struct regex_error_data { + char const *error_buffer; + int error_offset; +}; +#endif + +struct mmap_area; + +/** + * regex_arch_string return a string that represents the pointer width, the + * width of what the backend considers a size type, and the endianness of the + * system that this library was build for. (e.g. for x86_64: "8-8-el"). + * This is required when loading stored regular espressions. PCRE2 regular + * expressions are not portable across architectures that do not have a + * matching arch-string. + */ +char const *regex_arch_string(void) hidden; + +/** + * regex_verison returns the version string of the underlying regular + * regular expressions library. In the case of PCRE it just returns the + * result of pcre_version(). In the case of PCRE2, the very first time this + * function is called it allocates a buffer large enough to hold the version + * string and reads the PCRE2_CONFIG_VERSION option to fill the buffer. + * The allocated buffer will linger in memory until the calling process is being + * reaped. + * + * It may return NULL on error. + */ +char const *regex_version(void) hidden; +/** + * This constructor function allocates a buffer for a regex_data structure. + * The buffer is being initialized with zeroes. + */ +struct regex_data *regex_data_create(void) hidden; +/** + * This complementary destructor function frees the a given regex_data buffer. + * It also frees any non NULL member pointers with the appropriate pcreX_X_free + * function. For PCRE this function respects the extra_owned field and frees + * the pcre_extra data conditionally. Calling this function on a NULL pointer is + * save. + */ +void regex_data_free(struct regex_data *regex) hidden; +/** + * This function compiles the regular expression. Additionally, it prepares + * data structures required by the different underlying engines. For PCRE + * it calls pcre_study to generate optional data required for optimized + * execution of the compiled pattern. In the case of PCRE2, it allocates + * a pcre2_match_data structure of appropriate size to hold all possible + * matches created by the pattern. + * + * @arg regex If successful, the structure returned through *regex was allocated + * with regex_data_create and must be freed with regex_data_free. + * @arg pattern_string The pattern string that is to be compiled. + * @arg errordata A pointer to a regex_error_data structure must be passed + * to this function. This structure depends on the underlying + * implementation. It can be passed to regex_format_error + * to generate a human readable error message. + * @retval 0 on success + * @retval -1 on error + */ +int regex_prepare_data(struct regex_data **regex, char const *pattern_string, + struct regex_error_data *errordata) hidden; +/** + * This function loads a serialized precompiled pattern from a contiguous + * data region given by map_area. + * + * @arg map_area Description of the memory region holding a serialized + * representation of the precompiled pattern. + * @arg regex If successful, the structure returned through *regex was allocated + * with regex_data_create and must be freed with regex_data_free. + * @arg do_load_precompregex If non-zero precompiled patterns get loaded from + * the mmap region (ignored by PCRE1 back-end). + * @arg regex_compiled Set to true if a precompiled pattern was loaded + * into regex, otherwise set to false to indicate later + * compilation must occur + * + * @retval 0 on success + * @retval -1 on error + */ +int regex_load_mmap(struct mmap_area *map_area, + struct regex_data **regex, + int do_load_precompregex, + bool *regex_compiled) hidden; +/** + * This function stores a precompiled regular expression to a file. + * In the case of PCRE, it just dumps the binary representation of the + * precomplied pattern into a file. In the case of PCRE2, it uses the + * serialization function provided by the library. + * + * @arg regex The precomplied regular expression data. + * @arg fp A file stream specifying the output file. + * @arg do_write_precompregex If non-zero precompiled patterns are written to + * the output file (ignored by PCRE1 back-end). + */ +int regex_writef(struct regex_data *regex, FILE *fp, + int do_write_precompregex) hidden; +/** + * This function applies a precompiled pattern to a subject string and + * returns whether or not a match was found. + * + * @arg regex The precompiled pattern. + * @arg subject The subject string. + * @arg partial Boolean indicating if partial matches are wanted. A nonzero + * value is equivalent to specifying PCRE[2]_PARTIAL_SOFT as + * option to pcre_exec of pcre2_match. + * @retval REGEX_MATCH if a match was found + * @retval REGEX_MATCH_PARTIAL if a partial match was found + * @retval REGEX_NO_MATCH if no match was found + * @retval REGEX_ERROR if an error was encountered during the execution of the + * regular expression + */ +int regex_match(struct regex_data *regex, char const *subject, + int partial) hidden; +/** + * This function compares two compiled regular expressions (regex1 and regex2). + * It compares the binary representations of the compiled patterns. It is a very + * crude approximation because the binary representation holds data like + * reference counters, that has nothing to do with the actual state machine. + * + * @retval SELABEL_EQUAL if the pattern's binary representations are exactly + * the same + * @retval SELABEL_INCOMPARABLE otherwise + */ +int regex_cmp(struct regex_data *regex1, struct regex_data *regex2) hidden; +/** + * This function takes the error data returned by regex_prepare_data and turns + * it in to a human readable error message. + * If the buffer given to hold the error message is to small it truncates the + * message and indicates the truncation with an ellipsis ("...") at the end of + * the buffer. + * + * @arg error_data Error data as returned by regex_prepare_data. + * @arg buffer String buffer to hold the formated error string. + * @arg buf_size Total size of the given bufer in bytes. + */ +void regex_format_error(struct regex_error_data const *error_data, char *buffer, + size_t buf_size) hidden; +#endif /* SRC_REGEX_H_ */ diff --git a/src/reject_unknown.c b/src/reject_unknown.c new file mode 100644 index 0000000..5c1d360 --- /dev/null +++ b/src/reject_unknown.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_reject_unknown(void) +{ + int fd, ret, reject_unknown = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof(path), "%s/reject_unknown", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &reject_unknown) != 1) + return -1; + + return reject_unknown; +} + +hidden_def(security_reject_unknown); diff --git a/src/selinux_check_securetty_context.c b/src/selinux_check_securetty_context.c new file mode 100644 index 0000000..55d4e03 --- /dev/null +++ b/src/selinux_check_securetty_context.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "context_internal.h" + +int selinux_check_securetty_context(const char * tty_context) +{ + char *line = NULL; + char *start, *end = NULL; + size_t line_len = 0; + ssize_t len; + int found = -1; + FILE *fp; + fp = fopen(selinux_securetty_types_path(), "re"); + if (fp) { + context_t con = context_new(tty_context); + if (con) { + const char *type = context_type_get(con); + while ((len = getline(&line, &line_len, fp)) != -1) { + + if (line[len - 1] == '\n') + line[len - 1] = 0; + + /* Skip leading whitespace. */ + start = line; + while (*start && isspace(*start)) + start++; + if (!(*start)) + continue; + + end = start; + while (*end && !isspace(*end)) + end++; + if (*end) + *end++ = 0; + if (!strcmp(type, start)) { + found = 0; + break; + } + } + free(line); + context_free(con); + } + fclose(fp); + } + + return found; +} + +hidden_def(selinux_check_securetty_context) diff --git a/src/selinux_config.c b/src/selinux_config.c new file mode 100644 index 0000000..b06cb63 --- /dev/null +++ b/src/selinux_config.c @@ -0,0 +1,548 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "policy.h" +#include "selinux_internal.h" +#include "get_default_type_internal.h" + +#define SELINUXDEFAULT "targeted" +#define SELINUXTYPETAG "SELINUXTYPE=" +#define SELINUXTAG "SELINUX=" +#define SETLOCALDEFS "SETLOCALDEFS=" +#define REQUIRESEUSERS "REQUIRESEUSERS=" + +/* Indices for file paths arrays. */ +#define BINPOLICY 0 +#define CONTEXTS_DIR 1 +#define FILE_CONTEXTS 2 +#define HOMEDIR_CONTEXTS 3 +#define DEFAULT_CONTEXTS 4 +#define USER_CONTEXTS 5 +#define FAILSAFE_CONTEXT 6 +#define DEFAULT_TYPE 7 +#define BOOLEANS 8 +#define MEDIA_CONTEXTS 9 +#define REMOVABLE_CONTEXT 10 +#define CUSTOMIZABLE_TYPES 11 +#define USERS_DIR 12 +#define SEUSERS 13 +#define TRANSLATIONS 14 +#define NETFILTER_CONTEXTS 15 +#define FILE_CONTEXTS_HOMEDIR 16 +#define FILE_CONTEXTS_LOCAL 17 +#define SECURETTY_TYPES 18 +#define X_CONTEXTS 19 +#define COLORS 20 +#define VIRTUAL_DOMAIN 21 +#define VIRTUAL_IMAGE 22 +#define FILE_CONTEXT_SUBS 23 +#define SEPGSQL_CONTEXTS 24 +#define FILE_CONTEXT_SUBS_DIST 25 +#define LXC_CONTEXTS 26 +#define BOOLEAN_SUBS 27 +#define OPENSSH_CONTEXTS 28 +#define SYSTEMD_CONTEXTS 29 +#define SNAPPERD_CONTEXTS 30 +#define OPENRC_CONTEXTS 31 +#define NEL 32 + +/* Part of one-time lazy init */ +static pthread_once_t once = PTHREAD_ONCE_INIT; +static void init_selinux_config(void); + +/* New layout is relative to SELINUXDIR/policytype. */ +static char *file_paths[NEL]; +#define L1(l) L2(l) +#define L2(l)str##l +static const union file_path_suffixes_data { + struct { +#define S_(n, s) char L1(__LINE__)[sizeof(s)]; +#include "file_path_suffixes.h" +#undef S_ + }; + char str[0]; +} file_path_suffixes_data = { + { +#define S_(n, s) s, +#include "file_path_suffixes.h" +#undef S_ + } +}; +static const uint16_t file_path_suffixes_idx[NEL] = { +#define S_(n, s) [n] = offsetof(union file_path_suffixes_data, L1(__LINE__)), +#include "file_path_suffixes.h" +#undef S_ +}; + +#undef L1 +#undef L2 + +int selinux_getenforcemode(int *enforce) +{ + int ret = -1; + FILE *cfg = fopen(SELINUXCONFIG, "re"); + if (cfg) { + char *buf; + int len = sizeof(SELINUXTAG) - 1; + buf = malloc(selinux_page_size); + if (!buf) { + fclose(cfg); + return -1; + } + while (fgets_unlocked(buf, selinux_page_size, cfg)) { + if (strncmp(buf, SELINUXTAG, len)) + continue; + if (!strncasecmp + (buf + len, "enforcing", sizeof("enforcing") - 1)) { + *enforce = 1; + ret = 0; + break; + } else + if (!strncasecmp + (buf + len, "permissive", + sizeof("permissive") - 1)) { + *enforce = 0; + ret = 0; + break; + } else + if (!strncasecmp + (buf + len, "disabled", + sizeof("disabled") - 1)) { + *enforce = -1; + ret = 0; + break; + } + } + fclose(cfg); + free(buf); + } + return ret; +} + +hidden_def(selinux_getenforcemode) + +static char *selinux_policytype; + +int selinux_getpolicytype(char **type) +{ + __selinux_once(once, init_selinux_config); + if (!selinux_policytype) + return -1; + *type = strdup(selinux_policytype); + return *type ? 0 : -1; +} + +hidden_def(selinux_getpolicytype) + +static int setpolicytype(const char *type) +{ + free(selinux_policytype); + selinux_policytype = strdup(type); + return selinux_policytype ? 0 : -1; +} + +static char *selinux_policyroot = NULL; +static const char *selinux_rootpath = SELINUXDIR; + +static void init_selinux_config(void) +{ + int i, *intptr; + size_t line_len; + ssize_t len; + char *line_buf = NULL, *buf_p, *value, *type = NULL, *end; + FILE *fp; + + if (selinux_policyroot) + return; + + fp = fopen(SELINUXCONFIG, "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while ((len = getline(&line_buf, &line_len, fp)) > 0) { + if (line_buf[len - 1] == '\n') + line_buf[len - 1] = 0; + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + if (*buf_p == '#' || *buf_p == 0) + continue; + + if (!strncasecmp(buf_p, SELINUXTYPETAG, + sizeof(SELINUXTYPETAG) - 1)) { + type = strdup(buf_p + sizeof(SELINUXTYPETAG) - 1); + if (!type) + return; + end = type + strlen(type) - 1; + while ((end > type) && + (isspace(*end) || iscntrl(*end))) { + *end = 0; + end--; + } + if (setpolicytype(type) != 0) { + free(type); + return; + } + free(type); + continue; + } else if (!strncmp(buf_p, SETLOCALDEFS, + sizeof(SETLOCALDEFS) - 1)) { + value = buf_p + sizeof(SETLOCALDEFS) - 1; + intptr = &load_setlocaldefs; + } else if (!strncmp(buf_p, REQUIRESEUSERS, + sizeof(REQUIRESEUSERS) - 1)) { + value = buf_p + sizeof(REQUIRESEUSERS) - 1; + intptr = &require_seusers; + } else { + continue; + } + + if (isdigit(*value)) + *intptr = atoi(value); + else if (strncasecmp(value, "true", sizeof("true") - 1)) + *intptr = 1; + else if (strncasecmp + (value, "false", sizeof("false") - 1)) + *intptr = 0; + } + free(line_buf); + fclose(fp); + } + + if (!selinux_policytype && setpolicytype(SELINUXDEFAULT) != 0) + return; + + if (asprintf(&selinux_policyroot, "%s%s", SELINUXDIR, selinux_policytype) == -1) + return; + + for (i = 0; i < NEL; i++) + if (asprintf(&file_paths[i], "%s%s", + selinux_policyroot, + file_path_suffixes_data.str + + file_path_suffixes_idx[i]) + == -1) + return; +} + +static void fini_selinux_policyroot(void) __attribute__ ((destructor)); + +static void fini_selinux_policyroot(void) +{ + int i; + free(selinux_policyroot); + selinux_policyroot = NULL; + for (i = 0; i < NEL; i++) { + free(file_paths[i]); + file_paths[i] = NULL; + } + free(selinux_policytype); + selinux_policytype = NULL; +} + +void selinux_reset_config(void) +{ + fini_selinux_policyroot(); + init_selinux_config(); +} + +hidden_def(selinux_reset_config) + +static const char *get_path(int idx) +{ + __selinux_once(once, init_selinux_config); + return file_paths[idx]; +} + +const char *selinux_default_type_path(void) +{ + return get_path(DEFAULT_TYPE); +} + +hidden_def(selinux_default_type_path) + +const char *selinux_policy_root(void) +{ + __selinux_once(once, init_selinux_config); + return selinux_policyroot; +} + +int selinux_set_policy_root(const char *path) +{ + int i; + char *policy_type = strrchr(path, '/'); + if (!policy_type) { + errno = EINVAL; + return -1; + } + policy_type++; + + fini_selinux_policyroot(); + + selinux_policyroot = strdup(path); + if (! selinux_policyroot) + return -1; + + if (setpolicytype(policy_type) != 0) + return -1; + + for (i = 0; i < NEL; i++) + if (asprintf(&file_paths[i], "%s%s", + selinux_policyroot, + file_path_suffixes_data.str + + file_path_suffixes_idx[i]) + == -1) + return -1; + + return 0; +} + +const char *selinux_path(void) +{ + return selinux_rootpath; +} + +hidden_def(selinux_path) + +const char *selinux_default_context_path(void) +{ + return get_path(DEFAULT_CONTEXTS); +} + +hidden_def(selinux_default_context_path) + +const char *selinux_securetty_types_path(void) +{ + return get_path(SECURETTY_TYPES); +} + +hidden_def(selinux_securetty_types_path) + +const char *selinux_failsafe_context_path(void) +{ + return get_path(FAILSAFE_CONTEXT); +} + +hidden_def(selinux_failsafe_context_path) + +const char *selinux_removable_context_path(void) +{ + return get_path(REMOVABLE_CONTEXT); +} + +hidden_def(selinux_removable_context_path) + +const char *selinux_binary_policy_path(void) +{ + return get_path(BINPOLICY); +} + +hidden_def(selinux_binary_policy_path) + +const char *selinux_current_policy_path(void) +{ + int rc = 0; + int vers = 0; + static char policy_path[PATH_MAX]; + + if (selinux_mnt) { + snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt); + if (access(policy_path, F_OK) == 0 ) { + return policy_path; + } + } + vers = security_policyvers(); + do { + /* Check prior versions to see if old policy is available */ + snprintf(policy_path, sizeof(policy_path), "%s.%d", + selinux_binary_policy_path(), vers); + } while ((rc = access(policy_path, F_OK)) && --vers > 0); + + if (rc) return NULL; + return policy_path; +} + +hidden_def(selinux_current_policy_path) + +const char *selinux_file_context_path(void) +{ + return get_path(FILE_CONTEXTS); +} + +hidden_def(selinux_file_context_path) + +const char *selinux_homedir_context_path(void) +{ + return get_path(HOMEDIR_CONTEXTS); +} + +hidden_def(selinux_homedir_context_path) + +const char *selinux_media_context_path(void) +{ + return get_path(MEDIA_CONTEXTS); +} + +hidden_def(selinux_media_context_path) + +const char *selinux_customizable_types_path(void) +{ + return get_path(CUSTOMIZABLE_TYPES); +} + +hidden_def(selinux_customizable_types_path) + +const char *selinux_contexts_path(void) +{ + return get_path(CONTEXTS_DIR); +} + +const char *selinux_user_contexts_path(void) +{ + return get_path(USER_CONTEXTS); +} + +hidden_def(selinux_user_contexts_path) + +const char *selinux_booleans_path(void) +{ + return get_path(BOOLEANS); +} + +hidden_def(selinux_booleans_path) + +const char *selinux_users_path(void) +{ + return get_path(USERS_DIR); +} + +hidden_def(selinux_users_path) + +const char *selinux_usersconf_path(void) +{ + return get_path(SEUSERS); +} + +hidden_def(selinux_usersconf_path) + +const char *selinux_translations_path(void) +{ + return get_path(TRANSLATIONS); +} + +hidden_def(selinux_translations_path) + +const char *selinux_colors_path(void) +{ + return get_path(COLORS); +} + +hidden_def(selinux_colors_path) + +const char *selinux_netfilter_context_path(void) +{ + return get_path(NETFILTER_CONTEXTS); +} + +hidden_def(selinux_netfilter_context_path) + +const char *selinux_file_context_homedir_path(void) +{ + return get_path(FILE_CONTEXTS_HOMEDIR); +} + +hidden_def(selinux_file_context_homedir_path) + +const char *selinux_file_context_local_path(void) +{ + return get_path(FILE_CONTEXTS_LOCAL); +} + +hidden_def(selinux_file_context_local_path) + +const char *selinux_x_context_path(void) +{ + return get_path(X_CONTEXTS); +} + +hidden_def(selinux_x_context_path) + +const char *selinux_virtual_domain_context_path(void) +{ + return get_path(VIRTUAL_DOMAIN); +} + +hidden_def(selinux_virtual_domain_context_path) + +const char *selinux_virtual_image_context_path(void) +{ + return get_path(VIRTUAL_IMAGE); +} + +hidden_def(selinux_virtual_image_context_path) + +const char *selinux_lxc_contexts_path(void) +{ + return get_path(LXC_CONTEXTS); +} + +hidden_def(selinux_lxc_contexts_path) + +const char *selinux_openrc_contexts_path(void) +{ + return get_path(OPENRC_CONTEXTS); +} + +hidden_def(selinux_openrc_contexts_path) + +const char *selinux_openssh_contexts_path(void) +{ + return get_path(OPENSSH_CONTEXTS); +} + +hidden_def(selinux_openssh_contexts_path) + +const char *selinux_snapperd_contexts_path(void) +{ + return get_path(SNAPPERD_CONTEXTS); +} + +hidden_def(selinux_snapperd_contexts_path) + +const char *selinux_systemd_contexts_path(void) +{ + return get_path(SYSTEMD_CONTEXTS); +} + +hidden_def(selinux_systemd_contexts_path) + +const char * selinux_booleans_subs_path(void) { + return get_path(BOOLEAN_SUBS); +} + +hidden_def(selinux_booleans_subs_path) + +const char * selinux_file_context_subs_path(void) { + return get_path(FILE_CONTEXT_SUBS); +} + +hidden_def(selinux_file_context_subs_path) + +const char * selinux_file_context_subs_dist_path(void) { + return get_path(FILE_CONTEXT_SUBS_DIST); +} + +hidden_def(selinux_file_context_subs_dist_path) + +const char *selinux_sepgsql_context_path(void) +{ + return get_path(SEPGSQL_CONTEXTS); +} + +hidden_def(selinux_sepgsql_context_path) diff --git a/src/selinux_internal.h b/src/selinux_internal.h new file mode 100644 index 0000000..70b5025 --- /dev/null +++ b/src/selinux_internal.h @@ -0,0 +1,183 @@ +#include +#include +#include "dso.h" + +hidden_proto(selinux_mkload_policy) + hidden_proto(fini_selinuxmnt) + hidden_proto(set_selinuxmnt) + hidden_proto(selinuxfs_exists) + hidden_proto(security_disable) + hidden_proto(security_policyvers) + hidden_proto(security_load_policy) + hidden_proto(security_get_boolean_active) + hidden_proto(security_get_boolean_names) + hidden_proto(security_set_boolean) + hidden_proto(security_commit_booleans) + hidden_proto(security_check_context) + hidden_proto(security_check_context_raw) + hidden_proto(security_canonicalize_context) + hidden_proto(security_canonicalize_context_raw) + hidden_proto(security_compute_av) + hidden_proto(security_compute_av_raw) + hidden_proto(security_compute_av_flags) + hidden_proto(security_compute_av_flags_raw) + hidden_proto(security_compute_user) + hidden_proto(security_compute_user_raw) + hidden_proto(security_compute_create) + hidden_proto(security_compute_create_raw) + hidden_proto(security_compute_create_name) + hidden_proto(security_compute_create_name_raw) + hidden_proto(security_compute_member_raw) + hidden_proto(security_compute_relabel_raw) + hidden_proto(is_selinux_enabled) + hidden_proto(is_selinux_mls_enabled) + hidden_proto(freecon) + hidden_proto(freeconary) + hidden_proto(getprevcon) + hidden_proto(getprevcon_raw) + hidden_proto(getcon) + hidden_proto(getcon_raw) + hidden_proto(setcon_raw) + hidden_proto(getpeercon_raw) + hidden_proto(getpidcon_raw) + hidden_proto(getexeccon_raw) + hidden_proto(getfilecon) + hidden_proto(getfilecon_raw) + hidden_proto(lgetfilecon_raw) + hidden_proto(fgetfilecon_raw) + hidden_proto(setfilecon_raw) + hidden_proto(lsetfilecon_raw) + hidden_proto(fsetfilecon_raw) + hidden_proto(setexeccon) + hidden_proto(setexeccon_raw) + hidden_proto(getfscreatecon_raw) + hidden_proto(getkeycreatecon_raw) + hidden_proto(getsockcreatecon_raw) + hidden_proto(setfscreatecon_raw) + hidden_proto(setkeycreatecon_raw) + hidden_proto(setsockcreatecon_raw) + hidden_proto(security_getenforce) + hidden_proto(security_setenforce) + hidden_proto(security_deny_unknown) + hidden_proto(security_reject_unknown) + hidden_proto(security_get_checkreqprot) + hidden_proto(selinux_boolean_sub) + hidden_proto(selinux_current_policy_path) + hidden_proto(selinux_binary_policy_path) + hidden_proto(selinux_booleans_subs_path) + hidden_proto(selinux_default_context_path) + hidden_proto(selinux_securetty_types_path) + hidden_proto(selinux_failsafe_context_path) + hidden_proto(selinux_removable_context_path) + hidden_proto(selinux_virtual_domain_context_path) + hidden_proto(selinux_virtual_image_context_path) + hidden_proto(selinux_lxc_contexts_path) + hidden_proto(selinux_file_context_path) + hidden_proto(selinux_file_context_homedir_path) + hidden_proto(selinux_file_context_local_path) + hidden_proto(selinux_file_context_subs_dist_path) + hidden_proto(selinux_file_context_subs_path) + hidden_proto(selinux_netfilter_context_path) + hidden_proto(selinux_homedir_context_path) + hidden_proto(selinux_user_contexts_path) + hidden_proto(selinux_booleans_path) + hidden_proto(selinux_customizable_types_path) + hidden_proto(selinux_media_context_path) + hidden_proto(selinux_x_context_path) + hidden_proto(selinux_sepgsql_context_path) + hidden_proto(selinux_openrc_contexts_path) + hidden_proto(selinux_openssh_contexts_path) + hidden_proto(selinux_snapperd_contexts_path) + hidden_proto(selinux_systemd_contexts_path) + hidden_proto(selinux_path) + hidden_proto(selinux_check_passwd_access) + hidden_proto(selinux_check_securetty_context) + hidden_proto(matchpathcon_init_prefix) + hidden_proto(selinux_users_path) + hidden_proto(selinux_usersconf_path); +hidden_proto(selinux_translations_path); +hidden_proto(selinux_colors_path); +hidden_proto(selinux_getenforcemode); +hidden_proto(selinux_getpolicytype); +hidden_proto(selinux_raw_to_trans_context); +hidden_proto(selinux_trans_to_raw_context); + hidden_proto(selinux_raw_context_to_color); +hidden_proto(security_get_initial_context); +hidden_proto(security_get_initial_context_raw); +hidden_proto(selinux_reset_config); + +hidden void flush_class_cache(void); + +extern int load_setlocaldefs hidden; +extern int require_seusers hidden; +extern int selinux_page_size hidden; + +/* Make pthread_once optional */ +#pragma weak pthread_once +#pragma weak pthread_key_create +#pragma weak pthread_key_delete +#pragma weak pthread_setspecific + +/* Call handler iff the first call. */ +#define __selinux_once(ONCE_CONTROL, INIT_FUNCTION) \ + do { \ + if (pthread_once != NULL) \ + pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) = 2; \ + } \ + } while (0) + +/* Pthread key macros */ +#define __selinux_key_create(KEY, DESTRUCTOR) \ + (pthread_key_create != NULL ? pthread_key_create(KEY, DESTRUCTOR) : -1) + +#define __selinux_key_delete(KEY) \ + do { \ + if (pthread_key_delete != NULL) \ + pthread_key_delete(KEY); \ + } while (0) + +#define __selinux_setspecific(KEY, VALUE) \ + do { \ + if (pthread_setspecific != NULL) \ + pthread_setspecific(KEY, VALUE); \ + } while (0) + +/* selabel_lookup() is only thread safe if we're compiled with pthreads */ + +#pragma weak pthread_mutex_init +#pragma weak pthread_mutex_destroy +#pragma weak pthread_mutex_lock +#pragma weak pthread_mutex_unlock + +#define __pthread_mutex_init(LOCK, ATTR) \ + do { \ + if (pthread_mutex_init != NULL) \ + pthread_mutex_init(LOCK, ATTR); \ + } while (0) + +#define __pthread_mutex_destroy(LOCK) \ + do { \ + if (pthread_mutex_destroy != NULL) \ + pthread_mutex_destroy(LOCK); \ + } while (0) + +#define __pthread_mutex_lock(LOCK) \ + do { \ + if (pthread_mutex_lock != NULL) \ + pthread_mutex_lock(LOCK); \ + } while (0) + +#define __pthread_mutex_unlock(LOCK) \ + do { \ + if (pthread_mutex_unlock != NULL) \ + pthread_mutex_unlock(LOCK); \ + } while (0) + + +#define SELINUXDIR "/etc/selinux/" +#define SELINUXCONFIG SELINUXDIR "config" + +extern int has_selinux_config hidden; diff --git a/src/selinux_netlink.h b/src/selinux_netlink.h new file mode 100644 index 0000000..88ef551 --- /dev/null +++ b/src/selinux_netlink.h @@ -0,0 +1,31 @@ +/* + * Netlink event notifications for SELinux. + * + * Author: James Morris + */ +#ifndef _LINUX_SELINUX_NETLINK_H +#define _LINUX_SELINUX_NETLINK_H + +/* Message types. */ +#define SELNL_MSG_BASE 0x10 +enum { + SELNL_MSG_SETENFORCE = SELNL_MSG_BASE, + SELNL_MSG_POLICYLOAD, + SELNL_MSG_MAX +}; + +/* Multicast groups */ +#define SELNL_GRP_NONE 0x00000000 +#define SELNL_GRP_AVC 0x00000001 /* AVC notifications */ +#define SELNL_GRP_ALL 0xffffffff + +/* Message structures */ +struct selnl_msg_setenforce { + int32_t val; +}; + +struct selnl_msg_policyload { + uint32_t seqno; +}; + +#endif /* _LINUX_SELINUX_NETLINK_H */ diff --git a/src/selinux_restorecon.c b/src/selinux_restorecon.c new file mode 100644 index 0000000..5f18923 --- /dev/null +++ b/src/selinux_restorecon.c @@ -0,0 +1,1254 @@ +/* + * The majority of this code is from Android's + * external/libselinux/src/android.c and upstream + * selinux/policycoreutils/setfiles/restore.c + * + * See selinux_restorecon(3) for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "callbacks.h" +#include "selinux_internal.h" + +#define RESTORECON_LAST "security.restorecon_last" + +#define SYS_PATH "/sys" +#define SYS_PREFIX SYS_PATH "/" + +#define STAR_COUNT 1024 + +static struct selabel_handle *fc_sehandle = NULL; +static unsigned char *fc_digest = NULL; +static size_t fc_digest_len = 0; +static char *rootpath = NULL; +static int rootpathlen; + +/* Information on excluded fs and directories. */ +struct edir { + char *directory; + size_t size; + /* True if excluded by selinux_restorecon_set_exclude_list(3). */ + bool caller_excluded; +}; +#define CALLER_EXCLUDED true +static bool ignore_mounts; +static int exclude_non_seclabel_mounts(void); +static int exclude_count = 0; +static struct edir *exclude_lst = NULL; +static uint64_t fc_count = 0; /* Number of files processed so far */ +static uint64_t efile_count; /* Estimated total number of files */ + +/* Store information on directories with xattr's. */ +struct dir_xattr *dir_xattr_list; +static struct dir_xattr *dir_xattr_last; + +/* restorecon_flags for passing to restorecon_sb() */ +struct rest_flags { + bool nochange; + bool verbose; + bool progress; + bool mass_relabel; + bool set_specctx; + bool add_assoc; + bool ignore_digest; + bool recurse; + bool userealpath; + bool set_xdev; + bool abort_on_error; + bool syslog_changes; + bool log_matches; + bool ignore_noent; + bool warnonnomatch; +}; + +static void restorecon_init(void) +{ + struct selabel_handle *sehandle = NULL; + + if (!fc_sehandle) { + sehandle = selinux_restorecon_default_handle(); + selinux_restorecon_set_sehandle(sehandle); + } + + efile_count = 0; + if (!ignore_mounts) + efile_count = exclude_non_seclabel_mounts(); +} + +static pthread_once_t fc_once = PTHREAD_ONCE_INIT; + +/* + * Manage excluded directories: + * remove_exclude() - This removes any conflicting entries as there could be + * a case where a non-seclabel fs is mounted on /foo and + * then a seclabel fs is mounted on top of it. + * However if an entry has been added via + * selinux_restorecon_set_exclude_list(3) do not remove. + * + * add_exclude() - Add a directory/fs to be excluded from labeling. If it + * has already been added, then ignore. + * + * check_excluded() - Check if directory/fs is to be excluded when relabeling. + * + * file_system_count() - Calculates the number of files to be processed. + * The count is only used if SELINUX_RESTORECON_PROGRESS + * is set and a mass relabel is requested. + * + * exclude_non_seclabel_mounts() - Reads /proc/mounts to determine what + * non-seclabel mounts to exclude from + * relabeling. restorecon_init() will not + * call this function if the + * SELINUX_RESTORECON_IGNORE_MOUNTS + * flag is set. + * Setting SELINUX_RESTORECON_IGNORE_MOUNTS + * is useful where there is a non-seclabel fs + * mounted on /foo and then a seclabel fs is + * mounted on a directory below this. + */ +static void remove_exclude(const char *directory) +{ + int i; + + for (i = 0; i < exclude_count; i++) { + if (strcmp(directory, exclude_lst[i].directory) == 0 && + !exclude_lst[i].caller_excluded) { + free(exclude_lst[i].directory); + if (i != exclude_count - 1) + exclude_lst[i] = exclude_lst[exclude_count - 1]; + exclude_count--; + return; + } + } +} + +static int add_exclude(const char *directory, bool who) +{ + struct edir *tmp_list, *current; + size_t len = 0; + int i; + + /* Check if already present. */ + for (i = 0; i < exclude_count; i++) { + if (strcmp(directory, exclude_lst[i].directory) == 0) + return 0; + } + + if (directory == NULL || directory[0] != '/') { + selinux_log(SELINUX_ERROR, + "Full path required for exclude: %s.\n", + directory); + errno = EINVAL; + return -1; + } + + tmp_list = realloc(exclude_lst, + sizeof(struct edir) * (exclude_count + 1)); + if (!tmp_list) + goto oom; + + exclude_lst = tmp_list; + + len = strlen(directory); + while (len > 1 && directory[len - 1] == '/') + len--; + + current = (exclude_lst + exclude_count); + + current->directory = strndup(directory, len); + if (!current->directory) + goto oom; + + current->size = len; + current->caller_excluded = who; + exclude_count++; + return 0; + +oom: + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + return -1; +} + +static int check_excluded(const char *file) +{ + int i; + + for (i = 0; i < exclude_count; i++) { + if (strncmp(file, exclude_lst[i].directory, + exclude_lst[i].size) == 0) { + if (file[exclude_lst[i].size] == 0 || + file[exclude_lst[i].size] == '/') + return 1; + } + } + return 0; +} + +static int file_system_count(char *name) +{ + struct statvfs statvfs_buf; + int nfile = 0; + + memset(&statvfs_buf, 0, sizeof(statvfs_buf)); + if (!statvfs(name, &statvfs_buf)) + nfile = statvfs_buf.f_files - statvfs_buf.f_ffree; + + return nfile; +} + +/* + * This is called once when selinux_restorecon() is first called. + * Searches /proc/mounts for all file systems that do not support extended + * attributes and adds them to the exclude directory table. File systems + * that support security labels have the seclabel option, return + * approximate total file count. + */ +static int exclude_non_seclabel_mounts(void) +{ + struct utsname uts; + FILE *fp; + size_t len; + ssize_t num; + int index = 0, found = 0, nfile = 0; + char *mount_info[4]; + char *buf = NULL, *item; + + /* Check to see if the kernel supports seclabel */ + if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) + return 0; + if (is_selinux_enabled() <= 0) + return 0; + + fp = fopen("/proc/mounts", "re"); + if (!fp) + return 0; + + while ((num = getline(&buf, &len, fp)) != -1) { + found = 0; + index = 0; + item = strtok(buf, " "); + while (item != NULL) { + mount_info[index] = item; + index++; + if (index == 4) + break; + item = strtok(NULL, " "); + } + if (index < 4) { + selinux_log(SELINUX_ERROR, + "/proc/mounts record \"%s\" has incorrect format.\n", + buf); + continue; + } + + /* Remove pre-existing entry */ + remove_exclude(mount_info[1]); + + item = strtok(mount_info[3], ","); + while (item != NULL) { + if (strcmp(item, "seclabel") == 0) { + found = 1; + nfile += file_system_count(mount_info[1]); + break; + } + item = strtok(NULL, ","); + } + + /* Exclude mount points without the seclabel option */ + if (!found) { + if (add_exclude(mount_info[1], !CALLER_EXCLUDED) && + errno == ENOMEM) + assert(0); + } + } + + free(buf); + fclose(fp); + /* return estimated #Files + 5% for directories and hard links */ + return nfile * 1.05; +} + +/* Called by selinux_restorecon_xattr(3) to build a linked list of entries. */ +static int add_xattr_entry(const char *directory, bool delete_nonmatch, + bool delete_all) +{ + char *sha1_buf = NULL; + unsigned char *xattr_value = NULL; + ssize_t xattr_size; + size_t i; + int rc, digest_result; + struct dir_xattr *new_entry; + + if (!directory) { + errno = EINVAL; + return -1; + } + + xattr_value = malloc(fc_digest_len); + if (!xattr_value) + goto oom; + + xattr_size = getxattr(directory, RESTORECON_LAST, xattr_value, + fc_digest_len); + if (xattr_size < 0) { + free(xattr_value); + return 1; + } + + /* Convert entry to a hex encoded string. */ + sha1_buf = malloc(xattr_size * 2 + 1); + if (!sha1_buf) { + free(xattr_value); + goto oom; + } + + for (i = 0; i < (size_t)xattr_size; i++) + sprintf((&sha1_buf[i * 2]), "%02x", xattr_value[i]); + + rc = memcmp(fc_digest, xattr_value, fc_digest_len); + digest_result = rc ? NOMATCH : MATCH; + + if ((delete_nonmatch && rc != 0) || delete_all) { + digest_result = rc ? DELETED_NOMATCH : DELETED_MATCH; + rc = removexattr(directory, RESTORECON_LAST); + if (rc) { + selinux_log(SELINUX_ERROR, + "Error: %s removing xattr \"%s\" from: %s\n", + strerror(errno), RESTORECON_LAST, directory); + digest_result = ERROR; + } + } + free(xattr_value); + + /* Now add entries to link list. */ + new_entry = malloc(sizeof(struct dir_xattr)); + if (!new_entry) + goto oom; + new_entry->next = NULL; + + new_entry->directory = strdup(directory); + if (!new_entry->directory) { + free(new_entry); + free(sha1_buf); + goto oom; + } + + new_entry->digest = strdup(sha1_buf); + if (!new_entry->digest) { + free(new_entry->directory); + free(new_entry); + free(sha1_buf); + goto oom; + } + + new_entry->result = digest_result; + + if (!dir_xattr_list) { + dir_xattr_list = new_entry; + dir_xattr_last = new_entry; + } else { + dir_xattr_last->next = new_entry; + dir_xattr_last = new_entry; + } + + free(sha1_buf); + return 0; + +oom: + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + return -1; +} + +/* + * Support filespec services filespec_add(), filespec_eval() and + * filespec_destroy(). + * + * selinux_restorecon(3) uses filespec services when the + * SELINUX_RESTORECON_ADD_ASSOC flag is set for adding associations between + * an inode and a specification. + */ + +/* + * The hash table of associations, hashed by inode number. Chaining is used + * for collisions, with elements ordered by inode number in each bucket. + * Each hash bucket has a dummy header. + */ +#define HASH_BITS 16 +#define HASH_BUCKETS (1 << HASH_BITS) +#define HASH_MASK (HASH_BUCKETS-1) + +/* + * An association between an inode and a context. + */ +typedef struct file_spec { + ino_t ino; /* inode number */ + char *con; /* matched context */ + char *file; /* full pathname */ + struct file_spec *next; /* next association in hash bucket chain */ +} file_spec_t; + +static file_spec_t *fl_head; + +/* + * Try to add an association between an inode and a context. If there is a + * different context that matched the inode, then use the first context + * that matched. + */ +static int filespec_add(ino_t ino, const char *con, const char *file) +{ + file_spec_t *prevfl, *fl; + int h, ret; + struct stat64 sb; + + if (!fl_head) { + fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + if (!fl_head) + goto oom; + memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); + } + + h = (ino + (ino >> HASH_BITS)) & HASH_MASK; + for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; + prevfl = fl, fl = fl->next) { + if (ino == fl->ino) { + ret = lstat64(fl->file, &sb); + if (ret < 0 || sb.st_ino != ino) { + freecon(fl->con); + free(fl->file); + fl->file = strdup(file); + if (!fl->file) + goto oom; + fl->con = strdup(con); + if (!fl->con) + goto oom; + return 1; + } + + if (strcmp(fl->con, con) == 0) + return 1; + + selinux_log(SELINUX_ERROR, + "conflicting specifications for %s and %s, using %s.\n", + file, fl->file, fl->con); + free(fl->file); + fl->file = strdup(file); + if (!fl->file) + goto oom; + return 1; + } + + if (ino > fl->ino) + break; + } + + fl = malloc(sizeof(file_spec_t)); + if (!fl) + goto oom; + fl->ino = ino; + fl->con = strdup(con); + if (!fl->con) + goto oom_freefl; + fl->file = strdup(file); + if (!fl->file) + goto oom_freefl; + fl->next = prevfl->next; + prevfl->next = fl; + return 0; + +oom_freefl: + free(fl); +oom: + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + return -1; +} + +/* + * Evaluate the association hash table distribution. + */ +#ifdef DEBUG +static void filespec_eval(void) +{ + file_spec_t *fl; + int h, used, nel, len, longest; + + if (!fl_head) + return; + + used = 0; + longest = 0; + nel = 0; + for (h = 0; h < HASH_BUCKETS; h++) { + len = 0; + for (fl = fl_head[h].next; fl; fl = fl->next) + len++; + if (len) + used++; + if (len > longest) + longest = len; + nel += len; + } + + selinux_log(SELINUX_INFO, + "filespec hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", + nel, used, HASH_BUCKETS, longest); +} +#else +static void filespec_eval(void) +{ +} +#endif + +/* + * Destroy the association hash table. + */ +static void filespec_destroy(void) +{ + file_spec_t *fl, *tmp; + int h; + + if (!fl_head) + return; + + for (h = 0; h < HASH_BUCKETS; h++) { + fl = fl_head[h].next; + while (fl) { + tmp = fl; + fl = fl->next; + freecon(tmp->con); + free(tmp->file); + free(tmp); + } + fl_head[h].next = NULL; + } + free(fl_head); + fl_head = NULL; +} + +/* + * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if + * the type components differ, updating newtypecon if so. + */ +static int compare_types(char *curcon, char *newcon, char **newtypecon) +{ + int types_differ = 0; + context_t cona; + context_t conb; + int rc = 0; + + cona = context_new(curcon); + if (!cona) { + rc = -1; + goto out; + } + conb = context_new(newcon); + if (!conb) { + context_free(cona); + rc = -1; + goto out; + } + + types_differ = strcmp(context_type_get(cona), context_type_get(conb)); + if (types_differ) { + rc |= context_user_set(conb, context_user_get(cona)); + rc |= context_role_set(conb, context_role_get(cona)); + rc |= context_range_set(conb, context_range_get(cona)); + if (!rc) { + *newtypecon = strdup(context_str(conb)); + if (!*newtypecon) { + rc = -1; + goto err; + } + } + } + +err: + context_free(cona); + context_free(conb); +out: + return rc; +} + +static int restorecon_sb(const char *pathname, const struct stat *sb, + struct rest_flags *flags) +{ + char *newcon = NULL; + char *curcon = NULL; + char *newtypecon = NULL; + int rc; + bool updated = false; + const char *lookup_path = pathname; + float pc; + + if (rootpath) { + if (strncmp(rootpath, lookup_path, rootpathlen) != 0) { + selinux_log(SELINUX_ERROR, + "%s is not located in alt_rootpath %s\n", + lookup_path, rootpath); + return -1; + } + lookup_path += rootpathlen; + } + + if (rootpath != NULL && lookup_path[0] == '\0') + /* this is actually the root dir of the alt root. */ + rc = selabel_lookup_raw(fc_sehandle, &newcon, "/", + sb->st_mode); + else + rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path, + sb->st_mode); + + if (rc < 0) { + if (errno == ENOENT && flags->warnonnomatch) + selinux_log(SELINUX_INFO, + "Warning no default label for %s\n", + lookup_path); + + return 0; /* no match, but not an error */ + } + + if (flags->progress) { + fc_count++; + if (fc_count % STAR_COUNT == 0) { + if (flags->mass_relabel && efile_count > 0) { + pc = (fc_count < efile_count) ? (100.0 * + fc_count / efile_count) : 100; + fprintf(stdout, "\r%-.1f%%", (double)pc); + } else { + fprintf(stdout, "\r%" PRIu64 "k", fc_count / STAR_COUNT); + } + fflush(stdout); + } + } + + if (flags->add_assoc) { + rc = filespec_add(sb->st_ino, newcon, pathname); + + if (rc < 0) { + selinux_log(SELINUX_ERROR, + "filespec_add error: %s\n", pathname); + freecon(newcon); + return -1; + } + + if (rc > 0) { + /* Already an association and it took precedence. */ + freecon(newcon); + return 0; + } + } + + if (flags->log_matches) + selinux_log(SELINUX_INFO, "%s matched by %s\n", + pathname, newcon); + + if (lgetfilecon_raw(pathname, &curcon) < 0) { + if (errno != ENODATA) + goto err; + + curcon = NULL; + } + + if (curcon == NULL || strcmp(curcon, newcon) != 0) { + if (!flags->set_specctx && curcon && + (is_context_customizable(curcon) > 0)) { + if (flags->verbose) { + selinux_log(SELINUX_INFO, + "%s not reset as customized by admin to %s\n", + pathname, curcon); + } + goto out; + } + + if (!flags->set_specctx && curcon) { + /* If types different then update newcon. */ + rc = compare_types(curcon, newcon, &newtypecon); + if (rc) + goto err; + + if (newtypecon) { + freecon(newcon); + newcon = newtypecon; + } else { + goto out; + } + } + + if (!flags->nochange) { + if (lsetfilecon(pathname, newcon) < 0) + goto err; + updated = true; + } + + if (flags->verbose) + selinux_log(SELINUX_INFO, + "%s %s from %s to %s\n", + updated ? "Relabeled" : "Would relabel", + pathname, curcon, newcon); + + if (flags->syslog_changes && !flags->nochange) { + if (curcon) + syslog(LOG_INFO, + "relabeling %s from %s to %s\n", + pathname, curcon, newcon); + else + syslog(LOG_INFO, "labeling %s to %s\n", + pathname, newcon); + } + } + +out: + rc = 0; +out1: + freecon(curcon); + freecon(newcon); + return rc; +err: + selinux_log(SELINUX_ERROR, + "Could not set context for %s: %s\n", + pathname, strerror(errno)); + rc = -1; + goto out1; +} + +/* + * Public API + */ + +/* selinux_restorecon(3) - Main function that is responsible for labeling */ +int selinux_restorecon(const char *pathname_orig, + unsigned int restorecon_flags) +{ + struct rest_flags flags; + + flags.ignore_digest = (restorecon_flags & + SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; + flags.nochange = (restorecon_flags & + SELINUX_RESTORECON_NOCHANGE) ? true : false; + flags.verbose = (restorecon_flags & + SELINUX_RESTORECON_VERBOSE) ? true : false; + flags.progress = (restorecon_flags & + SELINUX_RESTORECON_PROGRESS) ? true : false; + flags.mass_relabel = (restorecon_flags & + SELINUX_RESTORECON_MASS_RELABEL) ? true : false; + flags.recurse = (restorecon_flags & + SELINUX_RESTORECON_RECURSE) ? true : false; + flags.set_specctx = (restorecon_flags & + SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; + flags.userealpath = (restorecon_flags & + SELINUX_RESTORECON_REALPATH) ? true : false; + flags.set_xdev = (restorecon_flags & + SELINUX_RESTORECON_XDEV) ? true : false; + flags.add_assoc = (restorecon_flags & + SELINUX_RESTORECON_ADD_ASSOC) ? true : false; + flags.abort_on_error = (restorecon_flags & + SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false; + flags.syslog_changes = (restorecon_flags & + SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false; + flags.log_matches = (restorecon_flags & + SELINUX_RESTORECON_LOG_MATCHES) ? true : false; + flags.ignore_noent = (restorecon_flags & + SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false; + flags.warnonnomatch = true; + ignore_mounts = (restorecon_flags & + SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false; + + bool issys; + bool setrestoreconlast = true; /* TRUE = set xattr RESTORECON_LAST + * FALSE = don't use xattr */ + struct stat sb; + struct statfs sfsb; + FTS *fts; + FTSENT *ftsent; + char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; + char *paths[2] = { NULL, NULL }; + int fts_flags, error, sverrno; + char *xattr_value = NULL; + ssize_t size; + dev_t dev_num = 0; + + if (flags.verbose && flags.progress) + flags.verbose = false; + + __selinux_once(fc_once, restorecon_init); + + if (!fc_sehandle) + return -1; + + if (fc_digest_len) { + xattr_value = malloc(fc_digest_len); + if (!xattr_value) + return -1; + } + + /* + * Convert passed-in pathname to canonical pathname by resolving + * realpath of containing dir, then appending last component name. + */ + if (flags.userealpath) { + char *basename_cpy = strdup(pathname_orig); + if (!basename_cpy) + goto realpatherr; + pathbname = basename(basename_cpy); + if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || + !strcmp(pathbname, "..")) { + pathname = realpath(pathname_orig, NULL); + if (!pathname) { + free(basename_cpy); + goto realpatherr; + } + } else { + char *dirname_cpy = strdup(pathname_orig); + if (!dirname_cpy) { + free(basename_cpy); + goto realpatherr; + } + pathdname = dirname(dirname_cpy); + pathdnamer = realpath(pathdname, NULL); + free(dirname_cpy); + if (!pathdnamer) { + free(basename_cpy); + goto realpatherr; + } + if (!strcmp(pathdnamer, "/")) + error = asprintf(&pathname, "/%s", pathbname); + else + error = asprintf(&pathname, "%s/%s", + pathdnamer, pathbname); + if (error < 0) { + free(basename_cpy); + goto oom; + } + } + free(basename_cpy); + } else { + pathname = strdup(pathname_orig); + if (!pathname) + goto oom; + } + + paths[0] = pathname; + issys = (!strcmp(pathname, SYS_PATH) || + !strncmp(pathname, SYS_PREFIX, + sizeof(SYS_PREFIX) - 1)) ? true : false; + + if (lstat(pathname, &sb) < 0) { + if (flags.ignore_noent && errno == ENOENT) { + free(xattr_value); + free(pathdnamer); + free(pathname); + return 0; + } else { + selinux_log(SELINUX_ERROR, + "lstat(%s) failed: %s\n", + pathname, strerror(errno)); + error = -1; + goto cleanup; + } + } + + /* Ignore restoreconlast if not a directory */ + if ((sb.st_mode & S_IFDIR) != S_IFDIR) + setrestoreconlast = false; + + if (!flags.recurse) { + if (check_excluded(pathname)) { + error = 0; + goto cleanup; + } + + error = restorecon_sb(pathname, &sb, &flags); + goto cleanup; + } + + /* Ignore restoreconlast on /sys */ + if (issys) + setrestoreconlast = false; + + /* Ignore restoreconlast on in-memory filesystems */ + if (setrestoreconlast && statfs(pathname, &sfsb) == 0) { + if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC) + setrestoreconlast = false; + } + + if (setrestoreconlast) { + size = getxattr(pathname, RESTORECON_LAST, xattr_value, + fc_digest_len); + + if (!flags.ignore_digest && (size_t)size == fc_digest_len && + memcmp(fc_digest, xattr_value, fc_digest_len) + == 0) { + selinux_log(SELINUX_INFO, + "Skipping restorecon as matching digest on: %s\n", + pathname); + error = 0; + goto cleanup; + } + } + + if (flags.set_xdev) + fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; + else + fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) + goto fts_err; + + ftsent = fts_read(fts); + if (!ftsent) + goto fts_err; + + /* + * Keep the inode of the first device. This is because the FTS_XDEV + * flag tells fts not to descend into directories with different + * device numbers, but fts will still give back the actual directory. + * By saving the device number of the directory that was passed to + * selinux_restorecon() and then skipping all actions on any + * directories with a different device number when the FTS_XDEV flag + * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2). + */ + dev_num = ftsent->fts_statp->st_dev; + + error = 0; + do { + /* If the FTS_XDEV flag is set and the device is different */ + if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num) + continue; + + switch (ftsent->fts_info) { + case FTS_DC: + selinux_log(SELINUX_ERROR, + "Directory cycle on %s.\n", + ftsent->fts_path); + errno = ELOOP; + error = -1; + goto out; + case FTS_DP: + continue; + case FTS_DNR: + selinux_log(SELINUX_ERROR, + "Could not read %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_NS: + selinux_log(SELINUX_ERROR, + "Could not stat %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_ERR: + selinux_log(SELINUX_ERROR, + "Error on %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_D: + if (issys && !selabel_partial_match(fc_sehandle, + ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (check_excluded(ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + /* fall through */ + default: + error |= restorecon_sb(ftsent->fts_path, + ftsent->fts_statp, &flags); + if (flags.warnonnomatch) + flags.warnonnomatch = false; + if (error && flags.abort_on_error) + goto out; + break; + } + } while ((ftsent = fts_read(fts)) != NULL); + + /* Labeling successful. Mark the top level directory as completed. */ + if (setrestoreconlast && !flags.nochange && !error && fc_digest) { + error = setxattr(pathname, RESTORECON_LAST, fc_digest, + fc_digest_len, 0); + if (!error && flags.verbose) + selinux_log(SELINUX_INFO, + "Updated digest for: %s\n", pathname); + } + +out: + if (flags.progress && flags.mass_relabel) + fprintf(stdout, "\r%s 100.0%%\n", pathname); + + sverrno = errno; + (void) fts_close(fts); + errno = sverrno; +cleanup: + if (flags.add_assoc) { + if (flags.verbose) + filespec_eval(); + filespec_destroy(); + } + free(pathdnamer); + free(pathname); + free(xattr_value); + return error; + +oom: + sverrno = errno; + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + errno = sverrno; + error = -1; + goto cleanup; + +realpatherr: + sverrno = errno; + selinux_log(SELINUX_ERROR, + "SELinux: Could not get canonical path for %s restorecon: %s.\n", + pathname_orig, strerror(errno)); + errno = sverrno; + error = -1; + goto cleanup; + +fts_err: + selinux_log(SELINUX_ERROR, + "fts error while labeling %s: %s\n", + paths[0], strerror(errno)); + error = -1; + goto cleanup; +} + +/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ +void selinux_restorecon_set_sehandle(struct selabel_handle *hndl) +{ + char **specfiles; + size_t num_specfiles; + + fc_sehandle = (struct selabel_handle *) hndl; + + /* + * Read digest if requested in selabel_open(3) and set global params. + */ + if (selabel_digest(fc_sehandle, &fc_digest, &fc_digest_len, + &specfiles, &num_specfiles) < 0) { + fc_digest = NULL; + fc_digest_len = 0; + } +} + +/* + * selinux_restorecon_default_handle(3) is called to set the global restorecon + * handle by a process if the default params are required. + */ +struct selabel_handle *selinux_restorecon_default_handle(void) +{ + struct selabel_handle *sehandle; + + struct selinux_opt fc_opts[] = { + { SELABEL_OPT_DIGEST, (char *)1 } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 1); + + if (!sehandle) { + selinux_log(SELINUX_ERROR, + "Error obtaining file context handle: %s\n", + strerror(errno)); + return NULL; + } + + return sehandle; +} + +/* + * selinux_restorecon_set_exclude_list(3) is called to add additional entries + * to be excluded from labeling checks. + */ +void selinux_restorecon_set_exclude_list(const char **exclude_list) +{ + int i; + struct stat sb; + + for (i = 0; exclude_list[i]; i++) { + if (lstat(exclude_list[i], &sb) < 0 && errno != EACCES) { + selinux_log(SELINUX_ERROR, + "lstat error on exclude path \"%s\", %s - ignoring.\n", + exclude_list[i], strerror(errno)); + break; + } + if (add_exclude(exclude_list[i], CALLER_EXCLUDED) && + errno == ENOMEM) + assert(0); + } +} + +/* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */ +int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath) +{ + int len; + + /* This should be NULL on first use */ + if (rootpath) + free(rootpath); + + rootpath = strdup(alt_rootpath); + if (!rootpath) { + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + return -1; + } + + /* trim trailing /, if present */ + len = strlen(rootpath); + while (len && (rootpath[len - 1] == '/')) + rootpath[--len] = '\0'; + rootpathlen = len; + + return 0; +} + +/* selinux_restorecon_xattr(3) - Find RESTORECON_LAST entries. */ +int selinux_restorecon_xattr(const char *pathname, unsigned int xattr_flags, + struct dir_xattr ***xattr_list) +{ + bool recurse = (xattr_flags & + SELINUX_RESTORECON_XATTR_RECURSE) ? true : false; + bool delete_nonmatch = (xattr_flags & + SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS) ? true : false; + bool delete_all = (xattr_flags & + SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS) ? true : false; + ignore_mounts = (xattr_flags & + SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS) ? true : false; + + int rc, fts_flags; + struct stat sb; + struct statfs sfsb; + struct dir_xattr *current, *next; + FTS *fts; + FTSENT *ftsent; + char *paths[2] = { NULL, NULL }; + + __selinux_once(fc_once, restorecon_init); + + if (!fc_sehandle || !fc_digest_len) + return -1; + + if (lstat(pathname, &sb) < 0) { + if (errno == ENOENT) + return 0; + + selinux_log(SELINUX_ERROR, + "lstat(%s) failed: %s\n", + pathname, strerror(errno)); + return -1; + } + + if (!recurse) { + if (statfs(pathname, &sfsb) == 0) { + if (sfsb.f_type == RAMFS_MAGIC || + sfsb.f_type == TMPFS_MAGIC) + return 0; + } + + if (check_excluded(pathname)) + return 0; + + rc = add_xattr_entry(pathname, delete_nonmatch, delete_all); + + if (!rc && dir_xattr_list) + *xattr_list = &dir_xattr_list; + else if (rc == -1) + return rc; + + return 0; + } + + paths[0] = (char *)pathname; + fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) { + selinux_log(SELINUX_ERROR, + "fts error on %s: %s\n", + paths[0], strerror(errno)); + return -1; + } + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_DP: + continue; + case FTS_D: + if (statfs(ftsent->fts_path, &sfsb) == 0) { + if (sfsb.f_type == RAMFS_MAGIC || + sfsb.f_type == TMPFS_MAGIC) + continue; + } + if (check_excluded(ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + rc = add_xattr_entry(ftsent->fts_path, + delete_nonmatch, delete_all); + if (rc == 1) + continue; + else if (rc == -1) + goto cleanup; + break; + default: + break; + } + } + + if (dir_xattr_list) + *xattr_list = &dir_xattr_list; + + (void) fts_close(fts); + return 0; + +cleanup: + rc = errno; + (void) fts_close(fts); + errno = rc; + + if (dir_xattr_list) { + /* Free any used memory */ + current = dir_xattr_list; + while (current) { + next = current->next; + free(current->directory); + free(current->digest); + free(current); + current = next; + } + } + return -1; +} diff --git a/src/selinuxswig.i b/src/selinuxswig.i new file mode 100644 index 0000000..9c5b926 --- /dev/null +++ b/src/selinuxswig.i @@ -0,0 +1,70 @@ +/* Authors: Dan Walsh + * James Athey + */ + +%module selinux +%{ + #include "../include/selinux/avc.h" + #include "../include/selinux/av_permissions.h" + #include "../include/selinux/context.h" + #include "../include/selinux/flask.h" + #include "../include/selinux/get_context_list.h" + #include "../include/selinux/get_default_type.h" + #include "../include/selinux/label.h" + #include "../include/selinux/restorecon.h" + #include "../include/selinux/selinux.h" +%} +%apply int *OUTPUT { int *enforce }; +%apply int *OUTPUT { size_t * }; + +%typedef unsigned mode_t; +%typedef unsigned pid_t; + +%typemap(in, numinputs=0) (char ***names, int *len) (char **temp1=NULL, int temp2) { + $1 = &temp1; + $2 = &temp2; +} + +%typemap(freearg) (char ***names, int *len) { + int i; + if (*$1) { + for (i = 0; i < *$2; i++) { + free((*$1)[i]); + } + free(*$1); + } +} + +%typemap(in, numinputs=0) (char ***) (char **temp=NULL) { + $1 = &temp; +} + +%typemap(freearg) (char ***) { + if (*$1) freeconary(*$1); +} + +/* Ignore functions that don't make sense when wrapped */ +%ignore freecon; +%ignore freeconary; + +/* Ignore functions that take a function pointer as an argument */ +%ignore set_matchpathcon_printf; +%ignore set_matchpathcon_invalidcon; +%ignore set_matchpathcon_canoncon; + +%ignore avc_add_callback; + +/* Ignore netlink stuff for now */ +%ignore avc_netlink_acquire_fd; +%ignore avc_netlink_release_fd; +%ignore avc_netlink_check_nb; + +%include "../include/selinux/avc.h" +%include "../include/selinux/av_permissions.h" +%include "../include/selinux/context.h" +%include "../include/selinux/flask.h" +%include "../include/selinux/get_context_list.h" +%include "../include/selinux/get_default_type.h" +%include "../include/selinux/label.h" +%include "../include/selinux/restorecon.h" +%include "../include/selinux/selinux.h" diff --git a/src/selinuxswig_python.i b/src/selinuxswig_python.i new file mode 100644 index 0000000..6eaab08 --- /dev/null +++ b/src/selinuxswig_python.i @@ -0,0 +1,161 @@ +/* Author: James Athey + */ + +/* Never build rpm_execcon interface unless you need to have ACG compatibility +#ifndef DISABLE_RPM +#define DISABLE_RPM +#endif +*/ + +%module selinux +%{ + #include "selinux/selinux.h" +%} + +%pythoncode %{ + +import shutil +import os + +DISABLED = -1 +PERMISSIVE = 0 +ENFORCING = 1 + +def restorecon(path, recursive=False, verbose=False, force=False): + """ Restore SELinux context on a given path + + Arguments: + path -- The pathname for the file or directory to be relabeled. + + Keyword arguments: + recursive -- Change files and directories file labels recursively (default False) + verbose -- Show changes in file labels (default False) + force -- Force reset of context to match file_context for customizable files, + and the default file context, changing the user, role, range portion as well + as the type (default False) + """ + + restorecon_flags = SELINUX_RESTORECON_IGNORE_DIGEST | SELINUX_RESTORECON_REALPATH + if recursive: + restorecon_flags |= SELINUX_RESTORECON_RECURSE + if verbose: + restorecon_flags |= SELINUX_RESTORECON_VERBOSE + if force: + restorecon_flags |= SELINUX_RESTORECON_SET_SPECFILE_CTX + selinux_restorecon(os.path.expanduser(path), restorecon_flags) + +def chcon(path, context, recursive=False): + """ Set the SELinux context on a given path """ + lsetfilecon(path, context) + if recursive: + for root, dirs, files in os.walk(path): + for name in files + dirs: + lsetfilecon(os.path.join(root, name), context) + +def copytree(src, dest): + """ An SELinux-friendly shutil.copytree method """ + shutil.copytree(src, dest) + restorecon(dest, recursive=True) + +def install(src, dest): + """ An SELinux-friendly shutil.move method """ + shutil.move(src, dest) + restorecon(dest, recursive=True) +%} + +/* security_get_boolean_names() typemap */ +%typemap(argout) (char ***names, int *len) { + PyObject* list = PyList_New(*$2); + int i; + for (i = 0; i < *$2; i++) { + PyList_SetItem(list, i, PyString_FromString((*$1)[i])); + } + $result = SWIG_Python_AppendOutput($result, list); +} + +/* return a sid along with the result */ +%typemap(argout) (security_id_t * sid) { + if (*$1) { + %append_output(SWIG_NewPointerObj(*$1, $descriptor(security_id_t), 0)); + } else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%typemap(in,numinputs=0) security_id_t *(security_id_t temp) { + $1 = &temp; +} + +%typemap(in, numinputs=0) void *(char *temp=NULL) { + $1 = temp; +} + +/* Makes security_compute_user() return a Python list of contexts */ +%typemap(argout) (char ***con) { + PyObject* plist; + int i, len = 0; + + if (*$1) { + while((*$1)[len]) + len++; + plist = PyList_New(len); + for (i = 0; i < len; i++) { + PyList_SetItem(plist, i, PyString_FromString((*$1)[i])); + } + } else { + plist = PyList_New(0); + } + + $result = SWIG_Python_AppendOutput($result, plist); +} + +/* Makes functions in get_context_list.h return a Python list of contexts */ +%typemap(argout) (char ***list) { + PyObject* plist; + int i; + + if (*$1) { + plist = PyList_New(result); + for (i = 0; i < result; i++) { + PyList_SetItem(plist, i, PyString_FromString((*$1)[i])); + } + } else { + plist = PyList_New(0); + } + /* Only return the Python list, don't need to return the length anymore */ + $result = plist; +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + freecon(*$1); + } + else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + free(*$1); + } + else { + Py_INCREF(Py_None); + %append_output(Py_None); + } +} + +%include "selinuxswig_python_exception.i" +%include "selinuxswig.i" diff --git a/src/selinuxswig_ruby.i b/src/selinuxswig_ruby.i new file mode 100644 index 0000000..51dacf8 --- /dev/null +++ b/src/selinuxswig_ruby.i @@ -0,0 +1,48 @@ +/* Author: Dan Walsh + Based on selinuxswig_python.i by James Athey + */ + +/* Never build rpm_execcon interface */ +#ifndef DISABLE_RPM +#define DISABLE_RPM +#endif + +%module selinux +%{ + #include "selinux/selinux.h" +%} + +/* return a sid along with the result */ +%typemap(argout) (security_id_t * sid) { + if (*$1) { + %append_output(SWIG_NewPointerObj(*$1, $descriptor(security_id_t), 0)); + } +} + +%typemap(in,numinputs=0) security_id_t *(security_id_t temp) { + $1 = &temp; +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + freecon(*$1); + } +} + +%typemap(in,noblock=1,numinputs=0) char ** (char * temp = 0) { + $1 = &temp; +} +%typemap(freearg,match="in") char ** ""; +%typemap(argout,noblock=1) char ** { + if (*$1) { + %append_output(SWIG_FromCharPtr(*$1)); + free(*$1); + } +} + +%include "selinuxswig.i" diff --git a/src/sestatus.c b/src/sestatus.c new file mode 100644 index 0000000..ed29dc5 --- /dev/null +++ b/src/sestatus.c @@ -0,0 +1,349 @@ +/* + * sestatus.c + * + * APIs to reference SELinux kernel status page (/selinux/status) + * + * Author: KaiGai Kohei + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "avc_internal.h" +#include "policy.h" + +/* + * copied from the selinux/include/security.h + */ +struct selinux_status_t +{ + uint32_t version; /* version number of thie structure */ + uint32_t sequence; /* sequence number of seqlock logic */ + uint32_t enforcing; /* current setting of enforcing mode */ + uint32_t policyload; /* times of policy reloaded */ + uint32_t deny_unknown; /* current setting of deny_unknown */ + /* version > 0 support above status */ +} __attribute((packed)); + +/* + * `selinux_status' + * + * NULL : not initialized yet + * MAP_FAILED : opened, but fallback-mode + * Valid Pointer : opened and mapped correctly + */ +static struct selinux_status_t *selinux_status = NULL; +static int selinux_status_fd; +static uint32_t last_seqno; + +static uint32_t fallback_sequence; +static int fallback_enforcing; +static int fallback_policyload; + +/* + * read_sequence + * + * A utility routine to reference kernel status page according to + * seqlock logic. Since selinux_status->sequence is an odd value during + * the kernel status page being updated, we try to synchronize completion + * of this updating, but we assume it is rare. + * The sequence is almost even number. + * + * __sync_synchronize is a portable memory barrier for various kind + * of architecture that is supported by GCC. + */ +static inline uint32_t read_sequence(struct selinux_status_t *status) +{ + uint32_t seqno = 0; + + do { + /* + * No need for sched_yield() in the first trial of + * this loop. + */ + if (seqno & 0x0001) + sched_yield(); + + seqno = status->sequence; + + __sync_synchronize(); + + } while (seqno & 0x0001); + + return seqno; +} + +/* + * selinux_status_updated + * + * It returns whether something has been happened since the last call. + * Because `selinux_status->sequence' shall be always incremented on + * both of setenforce/policyreload events, so differences from the last + * value informs us something has been happened. + */ +int selinux_status_updated(void) +{ + uint32_t curr_seqno; + int result = 0; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + curr_seqno = fallback_sequence; + } else { + curr_seqno = read_sequence(selinux_status); + } + + /* + * `curr_seqno' is always even-number, so it does not match with + * `last_seqno' being initialized to odd-number in the first call. + * We never return 'something was updated' in the first call, + * because this function focuses on status-updating since the last + * invocation. + */ + if (last_seqno & 0x0001) + last_seqno = curr_seqno; + + if (last_seqno != curr_seqno) + { + last_seqno = curr_seqno; + result = 1; + } + return result; +} + +/* + * selinux_status_getenforce + * + * It returns the current performing mode of SELinux. + * 1 means currently we run in enforcing mode, or 0 means permissive mode. + */ +int selinux_status_getenforce(void) +{ + uint32_t seqno; + uint32_t enforcing; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + return fallback_enforcing; + } + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + enforcing = selinux_status->enforcing; + + } while (seqno != read_sequence(selinux_status)); + + return enforcing ? 1 : 0; +} + +/* + * selinux_status_policyload + * + * It returns times of policy reloaded on the running system. + * Note that it is not a reliable value on fallback-mode until it receives + * the first event message via netlink socket, so, a correct usage of this + * value is to compare it with the previous value to detect policy reloaded + * event. + */ +int selinux_status_policyload(void) +{ + uint32_t seqno; + uint32_t policyload; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) { + if (avc_netlink_check_nb() < 0) + return -1; + + return fallback_policyload; + } + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + policyload = selinux_status->policyload; + + } while (seqno != read_sequence(selinux_status)); + + return policyload; +} + +/* + * selinux_status_deny_unknown + * + * It returns a guideline to handle undefined object classes or permissions. + * 0 means SELinux treats policy queries on undefined stuff being allowed, + * however, 1 means such queries are denied. + */ +int selinux_status_deny_unknown(void) +{ + uint32_t seqno; + uint32_t deny_unknown; + + if (selinux_status == NULL) { + errno = EINVAL; + return -1; + } + + if (selinux_status == MAP_FAILED) + return security_deny_unknown(); + + /* sequence must not be changed during references */ + do { + seqno = read_sequence(selinux_status); + + deny_unknown = selinux_status->deny_unknown; + + } while (seqno != read_sequence(selinux_status)); + + return deny_unknown ? 1 : 0; +} + +/* + * callback routines for fallback case using netlink socket + */ +static int fallback_cb_setenforce(int enforcing) +{ + fallback_sequence += 2; + fallback_enforcing = enforcing; + + return 0; +} + +static int fallback_cb_policyload(int policyload) +{ + fallback_sequence += 2; + fallback_policyload = policyload; + + return 0; +} + +/* + * selinux_status_open + * + * It tries to open and mmap kernel status page (/selinux/status). + * Since Linux 2.6.37 or later supports this feature, we may run + * fallback routine using a netlink socket on older kernels, if + * the supplied `fallback' is not zero. + * It returns 0 on success, or -1 on error. + */ +int selinux_status_open(int fallback) +{ + int fd; + char path[PATH_MAX]; + long pagesize; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize < 0) + return -1; + + snprintf(path, sizeof(path), "%s/status", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto error; + + selinux_status = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); + if (selinux_status == MAP_FAILED) { + close(fd); + goto error; + } + selinux_status_fd = fd; + last_seqno = (uint32_t)(-1); + + return 0; + +error: + /* + * If caller wants fallback routine, we try to provide + * an equivalent functionality using existing netlink + * socket, although it needs system call invocation to + * receive event notification. + */ + if (fallback && avc_netlink_open(0) == 0) { + union selinux_callback cb; + + /* register my callbacks */ + cb.func_setenforce = fallback_cb_setenforce; + selinux_set_callback(SELINUX_CB_SETENFORCE, cb); + cb.func_policyload = fallback_cb_policyload; + selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); + + /* mark as fallback mode */ + selinux_status = MAP_FAILED; + selinux_status_fd = avc_netlink_acquire_fd(); + last_seqno = (uint32_t)(-1); + + fallback_sequence = 0; + fallback_enforcing = security_getenforce(); + fallback_policyload = 0; + + return 1; + } + selinux_status = NULL; + + return -1; +} + +/* + * selinux_status_close + * + * It unmap and close the kernel status page, or close netlink socket + * if fallback mode. + */ +void selinux_status_close(void) +{ + long pagesize; + + /* not opened */ + if (selinux_status == NULL) + return; + + /* fallback-mode */ + if (selinux_status == MAP_FAILED) + { + avc_netlink_release_fd(); + avc_netlink_close(); + selinux_status = NULL; + return; + } + + pagesize = sysconf(_SC_PAGESIZE); + /* not much we can do other than leak memory */ + if (pagesize > 0) + munmap(selinux_status, pagesize); + selinux_status = NULL; + + close(selinux_status_fd); + selinux_status_fd = -1; + last_seqno = (uint32_t)(-1); +} diff --git a/src/setenforce.c b/src/setenforce.c new file mode 100644 index 0000000..09cad3c --- /dev/null +++ b/src/setenforce.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_setenforce(int value) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof path, "%s/enforce", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + + snprintf(buf, sizeof buf, "%d", value); + ret = write(fd, buf, strlen(buf)); + close(fd); + if (ret < 0) + return -1; + + return 0; +} + +hidden_def(security_setenforce) diff --git a/src/setexecfilecon.c b/src/setexecfilecon.c new file mode 100644 index 0000000..e72ba0d --- /dev/null +++ b/src/setexecfilecon.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include "selinux_internal.h" +#include "context_internal.h" + +int setexecfilecon(const char *filename, const char *fallback_type) +{ + char * mycon = NULL, *fcon = NULL, *newcon = NULL; + context_t con = NULL; + int rc = 0; + + if (is_selinux_enabled() < 1) + return 0; + + rc = getcon(&mycon); + if (rc < 0) + goto out; + + rc = getfilecon(filename, &fcon); + if (rc < 0) + goto out; + + rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &newcon); + if (rc < 0) + goto out; + + if (!strcmp(mycon, newcon)) { + /* No default transition, use fallback_type for now. */ + rc = -1; + con = context_new(mycon); + if (!con) + goto out; + if (context_type_set(con, fallback_type)) + goto out; + freecon(newcon); + newcon = strdup(context_str(con)); + if (!newcon) + goto out; + rc = 0; + } + + rc = setexeccon(newcon); + if (rc < 0) + goto out; + out: + + if (rc < 0 && security_getenforce() == 0) + rc = 0; + + context_free(con); + freecon(newcon); + freecon(fcon); + freecon(mycon); + return rc < 0 ? rc : 0; +} + +#ifndef DISABLE_RPM +int rpm_execcon(unsigned int verified __attribute__ ((unused)), + const char *filename, char *const argv[], char *const envp[]) +{ + int rc; + + rc = setexecfilecon(filename, "rpm_script_t"); + if (rc < 0) + return rc; + + return execve(filename, argv, envp); +} +#endif diff --git a/src/setfilecon.c b/src/setfilecon.c new file mode 100644 index 0000000..3f0200e --- /dev/null +++ b/src/setfilecon.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" + +int setfilecon_raw(const char *path, const char * context) +{ + int rc; + if (! context) { + errno=EINVAL; + return -1; + } + rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0); + if (rc < 0 && errno == ENOTSUP) { + char * ccontext = NULL; + int err = errno; + if ((getfilecon_raw(path, &ccontext) >= 0) && + (strcmp(context,ccontext) == 0)) { + rc = 0; + } else { + errno = err; + } + freecon(ccontext); + } + return rc; +} + +hidden_def(setfilecon_raw) + +int setfilecon(const char *path, const char *context) +{ + int ret; + char * rcontext; + + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + + ret = setfilecon_raw(path, rcontext); + + freecon(rcontext); + + return ret; +} diff --git a/src/setrans_client.c b/src/setrans_client.c new file mode 100644 index 0000000..fa188a8 --- /dev/null +++ b/src/setrans_client.c @@ -0,0 +1,444 @@ +/* Author: Trusted Computer Solutions, Inc. + * + * Modified: + * Yuichi Nakamura + - Stubs are used when DISABLE_SETRANS is defined, + it is to reduce size for such as embedded devices. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dso.h" +#include "selinux_internal.h" +#include "setrans_internal.h" + +#ifndef DISABLE_SETRANS +static unsigned char has_setrans; + +// Simple cache +static __thread char * prev_t2r_trans = NULL; +static __thread char * prev_t2r_raw = NULL; +static __thread char * prev_r2t_trans = NULL; +static __thread char * prev_r2t_raw = NULL; +static __thread char *prev_r2c_trans = NULL; +static __thread char * prev_r2c_raw = NULL; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; +static __thread char destructor_initialized; + +/* + * setransd_open + * + * This function opens a socket to the setransd. + * Returns: on success, a file descriptor ( >= 0 ) to the socket + * on error, a negative value + */ +static int setransd_open(void) +{ + struct sockaddr_un addr; + int fd; +#ifdef SOCK_CLOEXEC + fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (fd < 0 && errno == EINVAL) +#endif + { + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd >= 0) + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + close(fd); + return -1; + } + } + if (fd < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path)); + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(fd); + return -1; + } + + return fd; +} + +/* Returns: 0 on success, <0 on failure */ +static int +send_request(int fd, uint32_t function, const char *data1, const char *data2) +{ + struct msghdr msgh; + struct iovec iov[5]; + uint32_t data1_size; + uint32_t data2_size; + ssize_t count, expected; + unsigned int i; + + if (fd < 0) + return -1; + + if (!data1) + data1 = ""; + if (!data2) + data2 = ""; + + data1_size = strlen(data1) + 1; + data2_size = strlen(data2) + 1; + + iov[0].iov_base = &function; + iov[0].iov_len = sizeof(function); + iov[1].iov_base = &data1_size; + iov[1].iov_len = sizeof(data1_size); + iov[2].iov_base = &data2_size; + iov[2].iov_len = sizeof(data2_size); + iov[3].iov_base = (char *)data1; + iov[3].iov_len = data1_size; + iov[4].iov_base = (char *)data2; + iov[4].iov_len = data2_size; + memset(&msgh, 0, sizeof(msgh)); + msgh.msg_iov = iov; + msgh.msg_iovlen = sizeof(iov) / sizeof(iov[0]); + + expected = 0; + for (i = 0; i < sizeof(iov) / sizeof(iov[0]); i++) + expected += iov[i].iov_len; + + while (((count = sendmsg(fd, &msgh, MSG_NOSIGNAL)) < 0) + && (errno == EINTR)) ; + if (count < 0 || count != expected) + return -1; + + return 0; +} + +/* Returns: 0 on success, <0 on failure */ +static int +receive_response(int fd, uint32_t function, char **outdata, int32_t * ret_val) +{ + struct iovec resp_hdr[3]; + uint32_t func; + uint32_t data_size; + char *data; + struct iovec resp_data; + ssize_t count; + + if (fd < 0) + return -1; + + resp_hdr[0].iov_base = &func; + resp_hdr[0].iov_len = sizeof(func); + resp_hdr[1].iov_base = &data_size; + resp_hdr[1].iov_len = sizeof(data_size); + resp_hdr[2].iov_base = ret_val; + resp_hdr[2].iov_len = sizeof(*ret_val); + + while (((count = readv(fd, resp_hdr, 3)) < 0) && (errno == EINTR)) ; + if (count != (sizeof(func) + sizeof(data_size) + sizeof(*ret_val))) { + return -1; + } + + if (func != function || !data_size || data_size > MAX_DATA_BUF) { + return -1; + } + + data = malloc(data_size); + if (!data) + return -1; + /* coveriety doesn't realize that data will be initialized in readv */ + memset(data, 0, data_size); + + resp_data.iov_base = data; + resp_data.iov_len = data_size; + + while (((count = readv(fd, &resp_data, 1))) < 0 && (errno == EINTR)) ; + if (count < 0 || (uint32_t) count != data_size || + data[data_size - 1] != '\0') { + free(data); + return -1; + } + *outdata = data; + return 0; +} + +static int raw_to_trans_context(const char *raw, char **transp) +{ + int ret; + int32_t ret_val; + int fd; + + *transp = NULL; + + fd = setransd_open(); + if (fd < 0) + return fd; + + ret = send_request(fd, RAW_TO_TRANS_CONTEXT, raw, NULL); + if (ret) + goto out; + + ret = receive_response(fd, RAW_TO_TRANS_CONTEXT, transp, &ret_val); + if (ret) + goto out; + + ret = ret_val; + out: + close(fd); + return ret; +} + +static int trans_to_raw_context(const char *trans, char **rawp) +{ + int ret; + int32_t ret_val; + int fd; + + *rawp = NULL; + + fd = setransd_open(); + if (fd < 0) + return fd; + ret = send_request(fd, TRANS_TO_RAW_CONTEXT, trans, NULL); + if (ret) + goto out; + + ret = receive_response(fd, TRANS_TO_RAW_CONTEXT, rawp, &ret_val); + if (ret) + goto out; + + ret = ret_val; + out: + close(fd); + return ret; +} + +static int raw_context_to_color(const char *raw, char **colors) +{ + int ret; + int32_t ret_val; + int fd; + + fd = setransd_open(); + if (fd < 0) + return fd; + + ret = send_request(fd, RAW_CONTEXT_TO_COLOR, raw, NULL); + if (ret) + goto out; + + ret = receive_response(fd, RAW_CONTEXT_TO_COLOR, colors, &ret_val); + if (ret) + goto out; + + ret = ret_val; +out: + close(fd); + return ret; +} + +static void setrans_thread_destructor(void __attribute__((unused)) *unused) +{ + free(prev_t2r_trans); + free(prev_t2r_raw); + free(prev_r2t_trans); + free(prev_r2t_raw); + free(prev_r2c_trans); + free(prev_r2c_raw); +} + +void __attribute__((destructor)) setrans_lib_destructor(void); + +void hidden __attribute__((destructor)) setrans_lib_destructor(void) +{ + if (!has_setrans) + return; + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static inline void init_thread_destructor(void) +{ + if (!has_setrans) + return; + if (destructor_initialized == 0) { + __selinux_setspecific(destructor_key, (void *)1); + destructor_initialized = 1; + } +} + +static void init_context_translations(void) +{ + has_setrans = (access(SETRANS_UNIX_SOCKET, F_OK) == 0); + if (!has_setrans) + return; + if (__selinux_key_create(&destructor_key, setrans_thread_destructor) == 0) + destructor_key_initialized = 1; +} + +int selinux_trans_to_raw_context(const char * trans, + char ** rawp) +{ + if (!trans) { + *rawp = NULL; + return 0; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *rawp = strdup(trans); + goto out; + } + + if (prev_t2r_trans && strcmp(prev_t2r_trans, trans) == 0) { + *rawp = strdup(prev_t2r_raw); + } else { + free(prev_t2r_trans); + prev_t2r_trans = NULL; + free(prev_t2r_raw); + prev_t2r_raw = NULL; + if (trans_to_raw_context(trans, rawp)) + *rawp = strdup(trans); + if (*rawp) { + prev_t2r_trans = strdup(trans); + if (!prev_t2r_trans) + goto out; + prev_t2r_raw = strdup(*rawp); + if (!prev_t2r_raw) { + free(prev_t2r_trans); + prev_t2r_trans = NULL; + } + } + } + out: + return *rawp ? 0 : -1; +} + +hidden_def(selinux_trans_to_raw_context) + +int selinux_raw_to_trans_context(const char * raw, + char ** transp) +{ + if (!raw) { + *transp = NULL; + return 0; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *transp = strdup(raw); + goto out; + } + + if (prev_r2t_raw && strcmp(prev_r2t_raw, raw) == 0) { + *transp = strdup(prev_r2t_trans); + } else { + free(prev_r2t_raw); + prev_r2t_raw = NULL; + free(prev_r2t_trans); + prev_r2t_trans = NULL; + if (raw_to_trans_context(raw, transp)) + *transp = strdup(raw); + if (*transp) { + prev_r2t_raw = strdup(raw); + if (!prev_r2t_raw) + goto out; + prev_r2t_trans = strdup(*transp); + if (!prev_r2t_trans) { + free(prev_r2t_raw); + prev_r2t_raw = NULL; + } + } + } + out: + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_to_trans_context) + +int selinux_raw_context_to_color(const char * raw, char **transp) +{ + if (!raw) { + *transp = NULL; + return -1; + } + + __selinux_once(once, init_context_translations); + init_thread_destructor(); + + if (!has_setrans) { + *transp = strdup(raw); + goto out; + } + + if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) { + *transp = strdup(prev_r2c_trans); + } else { + free(prev_r2c_raw); + prev_r2c_raw = NULL; + free(prev_r2c_trans); + prev_r2c_trans = NULL; + if (raw_context_to_color(raw, transp)) + return -1; + if (*transp) { + prev_r2c_raw = strdup(raw); + if (!prev_r2c_raw) + goto out; + prev_r2c_trans = strdup(*transp); + if (!prev_r2c_trans) { + free(prev_r2c_raw); + prev_r2c_raw = NULL; + } + } + } + out: + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_context_to_color) +#else /*DISABLE_SETRANS*/ + +int selinux_trans_to_raw_context(const char * trans, + char ** rawp) +{ + if (!trans) { + *rawp = NULL; + return 0; + } + + *rawp = strdup(trans); + + return *rawp ? 0 : -1; +} + +hidden_def(selinux_trans_to_raw_context) + +int selinux_raw_to_trans_context(const char * raw, + char ** transp) +{ + if (!raw) { + *transp = NULL; + return 0; + } + *transp = strdup(raw); + + return *transp ? 0 : -1; +} + +hidden_def(selinux_raw_to_trans_context) +#endif /*DISABLE_SETRANS*/ diff --git a/src/setrans_internal.h b/src/setrans_internal.h new file mode 100644 index 0000000..b3bdca2 --- /dev/null +++ b/src/setrans_internal.h @@ -0,0 +1,10 @@ +/* Author: Trusted Computer Solutions, Inc. */ +#include + +#define SETRANS_UNIX_SOCKET SELINUX_TRANS_DIR "/.setrans-unix" + +#define RAW_TO_TRANS_CONTEXT 2 +#define TRANS_TO_RAW_CONTEXT 3 +#define RAW_CONTEXT_TO_COLOR 4 +#define MAX_DATA_BUF 8192 + diff --git a/src/setup.py b/src/setup.py new file mode 100644 index 0000000..b12e786 --- /dev/null +++ b/src/setup.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 + +from distutils.core import Extension, setup + +setup( + name="selinux", + version="2.9", + description="SELinux python 3 bindings", + author="SELinux Project", + author_email="selinux@vger.kernel.org", + ext_modules=[ + Extension('selinux._selinux', + sources=['selinuxswig_python.i'], + include_dirs=['../include'], + library_dirs=['.'], + libraries=['selinux']), + Extension('selinux.audit2why', + sources=['audit2why.c'], + include_dirs=['../include'], + library_dirs=['.'], + libraries=['selinux'], + extra_link_args=['-l:libsepol.a']) + ], +) diff --git a/src/seusers.c b/src/seusers.c new file mode 100644 index 0000000..572a7b0 --- /dev/null +++ b/src/seusers.c @@ -0,0 +1,331 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" + +/* Process line from seusers.conf and split into its fields. + Returns 0 on success, -1 on comments, and -2 on error. */ +static int process_seusers(const char *buffer, + char **luserp, + char **seuserp, char **levelp, int mls_enabled) +{ + char *newbuf = strdup(buffer); + char *luser = NULL, *seuser = NULL, *level = NULL; + char *start, *end; + int mls_found = 1; + + if (!newbuf) + goto err; + + start = newbuf; + while (isspace(*start)) + start++; + if (*start == '#' || *start == 0) { + free(newbuf); + return -1; /* Comment or empty line, skip over */ + } + end = strchr(start, ':'); + if (!end) + goto err; + *end = 0; + + luser = strdup(start); + if (!luser) + goto err; + + start = end + 1; + end = strchr(start, ':'); + if (!end) { + mls_found = 0; + + end = start; + while (*end && !isspace(*end)) + end++; + } + *end = 0; + + seuser = strdup(start); + if (!seuser) + goto err; + + if (!strcmp(seuser, "")) + goto err; + + /* Skip MLS if disabled, or missing. */ + if (!mls_enabled || !mls_found) + goto out; + + start = ++end; + while (*end && !isspace(*end)) + end++; + *end = 0; + + level = strdup(start); + if (!level) + goto err; + + if (!strcmp(level, "")) + goto err; + + out: + free(newbuf); + *luserp = luser; + *seuserp = seuser; + *levelp = level; + return 0; + err: + free(newbuf); + free(luser); + free(seuser); + free(level); + return -2; /* error */ +} + +int require_seusers hidden = 0; + +#include +#include + +static gid_t get_default_gid(const char *name) { + struct passwd pwstorage, *pwent = NULL; + gid_t gid = -1; + /* Allocate space for the getpwnam_r buffer */ + long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen <= 0) return -1; + char *rbuf = malloc(rbuflen); + if (rbuf == NULL) return -1; + + int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (retval == 0 && pwent) { + gid = pwent->pw_gid; + } + free(rbuf); + return gid; +} + +static int check_group(const char *group, const char *name, const gid_t gid) { + int match = 0; + int i, ng = 0; + gid_t *groups = NULL; + struct group gbuf, *grent = NULL; + + long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (rbuflen <= 0) + return 0; + char *rbuf; + + while(1) { + rbuf = malloc(rbuflen); + if (rbuf == NULL) + return 0; + int retval = getgrnam_r(group, &gbuf, rbuf, + rbuflen, &grent); + if ( retval == ERANGE ) + { + free(rbuf); + rbuflen = rbuflen * 2; + } else if ( retval != 0 || grent == NULL ) + { + goto done; + } else + { + break; + } + } + + if (getgrouplist(name, gid, NULL, &ng) < 0) { + if (ng == 0) + goto done; + groups = calloc(ng, sizeof(*groups)); + if (!groups) + goto done; + if (getgrouplist(name, gid, groups, &ng) < 0) + goto done; + } else { + /* WTF? ng was 0 and we didn't fail? Are we in 0 groups? */ + goto done; + } + + for (i = 0; i < ng; i++) { + if (grent->gr_gid == groups[i]) { + match = 1; + goto done; + } + } + + done: + free(groups); + free(rbuf); + return match; +} + +int getseuserbyname(const char *name, char **r_seuser, char **r_level) +{ + FILE *cfg = NULL; + size_t size = 0; + char *buffer = NULL; + int rc; + unsigned long lineno = 0; + int mls_enabled = is_selinux_mls_enabled(); + + char *username = NULL; + char *seuser = NULL; + char *level = NULL; + char *groupseuser = NULL; + char *grouplevel = NULL; + char *defaultseuser = NULL; + char *defaultlevel = NULL; + + gid_t gid = get_default_gid(name); + + cfg = fopen(selinux_usersconf_path(), "re"); + if (!cfg) + goto nomatch; + + __fsetlocking(cfg, FSETLOCKING_BYCALLER); + while (getline(&buffer, &size, cfg) > 0) { + ++lineno; + rc = process_seusers(buffer, &username, &seuser, &level, + mls_enabled); + if (rc == -1) + continue; /* comment, skip */ + if (rc == -2) { + fprintf(stderr, "%s: error on line %lu, skipping...\n", + selinux_usersconf_path(), lineno); + continue; + } + + if (!strcmp(username, name)) + break; + + if (username[0] == '%' && + !groupseuser && + check_group(&username[1], name, gid)) { + groupseuser = seuser; + grouplevel = level; + } else { + if (!defaultseuser && + !strcmp(username, "__default__")) { + defaultseuser = seuser; + defaultlevel = level; + } else { + free(seuser); + free(level); + } + } + free(username); + username = NULL; + seuser = NULL; + } + + free(buffer); + fclose(cfg); + + if (seuser) { + free(username); + free(defaultseuser); + free(defaultlevel); + free(groupseuser); + free(grouplevel); + *r_seuser = seuser; + *r_level = level; + return 0; + } + + if (groupseuser) { + free(defaultseuser); + free(defaultlevel); + *r_seuser = groupseuser; + *r_level = grouplevel; + return 0; + } + + if (defaultseuser) { + *r_seuser = defaultseuser; + *r_level = defaultlevel; + return 0; + } + + nomatch: + if (require_seusers) + return -1; + + /* Fall back to the Linux username and no level. */ + *r_seuser = strdup(name); + if (!(*r_seuser)) + return -1; + *r_level = NULL; + return 0; +} + +int getseuser(const char *username, const char *service, + char **r_seuser, char **r_level) { + int ret = -1; + int len = 0; + char *seuser = NULL; + char *level = NULL; + char *buffer = NULL; + size_t size = 0; + char *rec = NULL; + char *path=NULL; + FILE *fp = NULL; + if (asprintf(&path,"%s/logins/%s", selinux_policy_root(), username) < 0) + goto err; + fp = fopen(path, "re"); + free(path); + if (fp == NULL) goto err; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + while (getline(&buffer, &size, fp) > 0) { + if (strncmp(buffer, "*:", 2) == 0) { + free(rec); + rec = strdup(buffer); + continue; + } + if (!service) + continue; + len = strlen(service); + if ((strncmp(buffer, service, len) == 0) && + (buffer[len] == ':')) { + free(rec); + rec = strdup(buffer); + break; + } + } + + if (! rec) goto err; + seuser = strchr(rec, ':'); + if (! seuser) goto err; + + seuser++; + level = strchr(seuser, ':'); + if (! level) goto err; + *level = 0; + level++; + *r_seuser = strdup(seuser); + if (! *r_seuser) goto err; + + len = strlen(level); + if (len && level[len-1] == '\n') + level[len-1] = 0; + + *r_level = strdup(level); + if (! *r_level) { + free(*r_seuser); + goto err; + } + ret = 0; + + err: + free(buffer); + if (fp) fclose(fp); + free(rec); + + return (ret ? getseuserbyname(username, r_seuser, r_level) : ret); +} diff --git a/src/sha1.c b/src/sha1.c new file mode 100644 index 0000000..9bcbb6e --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,220 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// LibSha1 +// +// Implementation of SHA1 hash function. +// Original author: Steve Reid +// Contributions by: James H. Brown , Saul Kravitz , +// and Ralph Giles +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +// Modified to: +// - stop symbols being exported for libselinux shared library - October 2015 +// Richard Haines +// - Not cast the workspace from a byte array to a CHAR64LONG16 due to allignment isses. +// Fixes: +// sha1.c:73:33: error: cast from 'uint8_t *' (aka 'unsigned char *') to 'CHAR64LONG16 *' increases required alignment from 1 to 4 [-Werror,-Wcast-align] +// CHAR64LONG16* block = (CHAR64LONG16*) workspace; +// William Roberts +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "sha1.h" +#include "dso.h" +#include + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union +{ + uint8_t c [64]; + uint32_t l [16]; +} CHAR64LONG16; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +// blk0() and blk() perform the initial expand. +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) + +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +// (R0+R1), R2, R3, R4 are the different operations used in SHA1 +#define R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk0(i)+ 0x5A827999 + rol(v,5); w=rol(w,30); +#define R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk(i) + 0x5A827999 + rol(v,5); w=rol(w,30); +#define R2(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0x6ED9EBA1 + rol(v,5); w=rol(w,30); +#define R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + blk(i) + 0x8F1BBCDC + rol(v,5); w=rol(w,30); +#define R4(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0xCA62C1D6 + rol(v,5); w=rol(w,30); + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TransformFunction +// +// Hash a single 512-bit block. This is the core of the algorithm +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static +void + TransformFunction + ( + uint32_t state[5], + const uint8_t buffer[64] + ) +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t e; + CHAR64LONG16 workspace; + CHAR64LONG16* block = &workspace; + + memcpy( block, buffer, 64 ); + + // Copy context->state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + // Add the working vars back into context.state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Initialise +// +// Initialises an SHA1 Context. Use this to initialise/reset a context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Initialise + ( + Sha1Context* Context + ) +{ + // SHA1 initialization constants + Context->State[0] = 0x67452301; + Context->State[1] = 0xEFCDAB89; + Context->State[2] = 0x98BADCFE; + Context->State[3] = 0x10325476; + Context->State[4] = 0xC3D2E1F0; + Context->Count[0] = 0; + Context->Count[1] = 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Update +// +// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Update + ( + Sha1Context* Context, + void* Buffer, + uint32_t BufferSize + ) +{ + uint32_t i; + uint32_t j; + + j = (Context->Count[0] >> 3) & 63; + if( (Context->Count[0] += BufferSize << 3) < (BufferSize << 3) ) + { + Context->Count[1]++; + } + + Context->Count[1] += (BufferSize >> 29); + if( (j + BufferSize) > 63 ) + { + i = 64 - j; + memcpy( &Context->Buffer[j], Buffer, i ); + TransformFunction(Context->State, Context->Buffer); + for( ; i + 63 < BufferSize; i += 64 ) + { + TransformFunction(Context->State, (uint8_t*)Buffer + i); + } + j = 0; + } + else + { + i = 0; + } + + memcpy( &Context->Buffer[j], &((uint8_t*)Buffer)[i], BufferSize - i ); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Finalise +// +// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After +// calling this, Sha1Initialised must be used to reuse the context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void hidden + Sha1Finalise + ( + Sha1Context* Context, + SHA1_HASH* Digest + ) +{ + uint32_t i; + uint8_t finalcount[8]; + + for( i=0; i<8; i++ ) + { + finalcount[i] = (unsigned char)((Context->Count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); // Endian independent + } + Sha1Update( Context, (uint8_t*)"\x80", 1 ); + while( (Context->Count[0] & 504) != 448 ) + { + Sha1Update( Context, (uint8_t*)"\0", 1 ); + } + + Sha1Update( Context, finalcount, 8 ); // Should cause a Sha1TransformFunction() + for( i=0; ibytes[i] = (uint8_t)((Context->State[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 0000000..eac3c19 --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// LibSha1 +// +// Implementation of SHA1 hash function. +// Original author: Steve Reid +// Contributions by: James H. Brown , Saul Kravitz , +// and Ralph Giles +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef _sha1_h_ +#define _sha1_h_ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Sha1Context - This must be initialised using Sha1Initialised. Do not modify the contents of this structure directly. +typedef struct +{ + uint32_t State[5]; + uint32_t Count[2]; + uint8_t Buffer[64]; +} Sha1Context; + +#define SHA1_HASH_SIZE ( 160 / 8 ) + +typedef struct +{ + uint8_t bytes [SHA1_HASH_SIZE]; +} SHA1_HASH; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Initialise +// +// Initialises an SHA1 Context. Use this to initialise/reset a context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Initialise + ( + Sha1Context* Context + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Update +// +// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Update + ( + Sha1Context* Context, + void* Buffer, + uint32_t BufferSize + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Finalise +// +// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After +// calling this, Sha1Initialised must be used to reuse the context. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Finalise + ( + Sha1Context* Context, + SHA1_HASH* Digest + ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif //_sha1_h_ diff --git a/src/stringrep.c b/src/stringrep.c new file mode 100644 index 0000000..2d83f96 --- /dev/null +++ b/src/stringrep.c @@ -0,0 +1,349 @@ +/* + * String representation support for classes and permissions. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include "mapping.h" + +#define MAXVECTORS 8*sizeof(access_vector_t) + +struct discover_class_node { + char *name; + security_class_t value; + char **perms; + + struct discover_class_node *next; +}; + +static struct discover_class_node *discover_class_cache = NULL; + +static struct discover_class_node * get_class_cache_entry_name(const char *s) +{ + struct discover_class_node *node = discover_class_cache; + + for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); + + return node; +} + +static struct discover_class_node * get_class_cache_entry_value(security_class_t c) +{ + struct discover_class_node *node = discover_class_cache; + + for (; node != NULL && c != node->value; node = node->next); + + return node; +} + +static struct discover_class_node * discover_class(const char *s) +{ + int fd, ret; + char path[PATH_MAX]; + char buf[20]; + DIR *dir; + struct dirent *dentry; + size_t i; + + struct discover_class_node *node; + + if (!selinux_mnt) { + errno = ENOENT; + return NULL; + } + + /* allocate a node */ + node = malloc(sizeof(struct discover_class_node)); + if (node == NULL) + return NULL; + + /* allocate array for perms */ + node->perms = calloc(MAXVECTORS,sizeof(char*)); + if (node->perms == NULL) + goto err1; + + /* load up the name */ + node->name = strdup(s); + if (node->name == NULL) + goto err2; + + /* load up class index */ + snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto err3; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + goto err3; + + if (sscanf(buf, "%hu", &node->value) != 1) + goto err3; + + /* load up permission indicies */ + snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); + dir = opendir(path); + if (dir == NULL) + goto err3; + + dentry = readdir(dir); + while (dentry != NULL) { + unsigned int value; + struct stat m; + + snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto err4; + + if (fstat(fd, &m) < 0) { + close(fd); + goto err4; + } + + if (m.st_mode & S_IFDIR) { + close(fd); + dentry = readdir(dir); + continue; + } + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + goto err4; + + if (sscanf(buf, "%u", &value) != 1) + goto err4; + + if (value == 0 || value > MAXVECTORS) + goto err4; + + node->perms[value-1] = strdup(dentry->d_name); + if (node->perms[value-1] == NULL) + goto err4; + + dentry = readdir(dir); + } + closedir(dir); + + node->next = discover_class_cache; + discover_class_cache = node; + + return node; + +err4: + closedir(dir); + for (i=0; iperms[i]); +err3: + free(node->name); +err2: + free(node->perms); +err1: + free(node); + return NULL; +} + +hidden void flush_class_cache(void) +{ + struct discover_class_node *cur = discover_class_cache, *prev = NULL; + size_t i; + + while (cur != NULL) { + free(cur->name); + + for (i = 0; i < MAXVECTORS; i++) + free(cur->perms[i]); + + free(cur->perms); + + prev = cur; + cur = cur->next; + + free(prev); + } + + discover_class_cache = NULL; +} + +security_class_t string_to_security_class(const char *s) +{ + struct discover_class_node *node; + + node = get_class_cache_entry_name(s); + if (node == NULL) { + node = discover_class(s); + + if (node == NULL) { + errno = EINVAL; + return 0; + } + } + + return map_class(node->value); +} + +security_class_t mode_to_security_class(mode_t m) { + + if (S_ISREG(m)) + return string_to_security_class("file"); + if (S_ISDIR(m)) + return string_to_security_class("dir"); + if (S_ISCHR(m)) + return string_to_security_class("chr_file"); + if (S_ISBLK(m)) + return string_to_security_class("blk_file"); + if (S_ISFIFO(m)) + return string_to_security_class("fifo_file"); + if (S_ISLNK(m)) + return string_to_security_class("lnk_file"); + if (S_ISSOCK(m)) + return string_to_security_class("sock_file"); + + errno=EINVAL; + return 0; +} + +access_vector_t string_to_av_perm(security_class_t tclass, const char *s) +{ + struct discover_class_node *node; + security_class_t kclass = unmap_class(tclass); + + node = get_class_cache_entry_value(kclass); + if (node != NULL) { + size_t i; + for (i=0; iperms[i] != NULL; i++) + if (strcmp(node->perms[i],s) == 0) + return map_perm(tclass, 1<name; +} + +const char *security_av_perm_to_string(security_class_t tclass, + access_vector_t av) +{ + struct discover_class_node *node; + size_t i; + + av = unmap_perm(tclass, av); + tclass = unmap_class(tclass); + + node = get_class_cache_entry_value(tclass); + if (av && node) + for (i = 0; iperms[i]; + + return NULL; +} + +int security_av_string(security_class_t tclass, access_vector_t av, char **res) +{ + unsigned int i = 0; + size_t len = 5; + access_vector_t tmp = av; + int rc = 0; + const char *str; + char *ptr; + + /* first pass computes the required length */ + while (tmp) { + if (tmp & 1) { + str = security_av_perm_to_string(tclass, av & (1<>= 1; + i++; + } + + *res = malloc(len); + if (!*res) { + rc = -1; + goto out; + } + + /* second pass constructs the string */ + i = 0; + tmp = av; + ptr = *res; + + if (!av) { + sprintf(ptr, "null"); + goto out; + } + + ptr += sprintf(ptr, "{ "); + while (tmp) { + if (tmp & 1) + ptr += sprintf(ptr, "%s ", security_av_perm_to_string( + tclass, av & (1<>= 1; + i++; + } + sprintf(ptr, "}"); +out: + return rc; +} + +void print_access_vector(security_class_t tclass, access_vector_t av) +{ + const char *permstr; + access_vector_t bit = 1; + + if (av == 0) { + printf(" null"); + return; + } + + printf(" {"); + + while (av) { + if (av & bit) { + permstr = security_av_perm_to_string(tclass, bit); + if (!permstr) + break; + printf(" %s", permstr); + av &= ~bit; + } + bit <<= 1; + } + + if (av) + printf(" 0x%x", av); + printf(" }"); +} diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100644 index 0000000..5cd0102 --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1,27 @@ +avcstat +compute_av +compute_create +compute_member +compute_relabel +compute_user +getconlist +getdefaultcon +getenforce +getfilecon +getpidcon +getsebool +getseuser +matchpathcon +policyvers +sefcontext_compile +selabel_digest +selabel_lookup +selabel_lookup_best_match +selabel_partial_match +selinux_check_securetty_context +selinuxenabled +selinuxexeccon +setenforce +setfilecon +togglesebool +selinux_check_access diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000..3615063 --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,76 @@ +# Installation directories. +PREFIX ?= /usr +SBINDIR ?= $(PREFIX)/sbin + +OS ?= $(shell uname) + +ifeq ($(shell $(CC) -v 2>&1 | grep "clang"),) +COMPILER ?= gcc +else +COMPILER ?= clang +endif + +ifeq ($(COMPILER), gcc) +EXTRA_CFLAGS = -fipa-pure-const -Wpacked-bitfield-compat -Wsync-nand -Wcoverage-mismatch \ + -Wcpp -Wformat-contains-nul -Wnormalized=nfc -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines -Wjump-misses-init \ + -Wno-suggest-attribute=pure -Wno-suggest-attribute=const +endif + +MAX_STACK_SIZE=8192 +CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissing-include-dirs \ + -Wunused -Wunknown-pragmas -Wstrict-aliasing -Wshadow -Wpointer-arith \ + -Wbad-function-cast -Wcast-align -Wwrite-strings -Waggregate-return \ + -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes \ + -Wmissing-declarations -Wmissing-noreturn -Wmissing-format-attribute \ + -Wredundant-decls -Wnested-externs -Winline -Winvalid-pch -Wvolatile-register-var \ + -Wdisabled-optimization -Wbuiltin-macro-redefined \ + -Wattributes -Wmultichar \ + -Wdeprecated-declarations -Wdiv-by-zero -Wdouble-promotion -Wendif-labels -Wextra \ + -Wformat-extra-args -Wformat-zero-length -Wformat=2 -Wmultichar \ + -Woverflow -Wpointer-to-int-cast -Wpragmas \ + -Wno-missing-field-initializers -Wno-sign-compare \ + -Wno-format-nonliteral -Wframe-larger-than=$(MAX_STACK_SIZE) -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 \ + -fstack-protector-all --param=ssp-buffer-size=4 -fexceptions \ + -fasynchronous-unwind-tables -fdiagnostics-show-option -funit-at-a-time \ + -Werror -Wno-aggregate-return -Wno-redundant-decls -Wstrict-overflow=5 \ + $(EXTRA_CFLAGS) + +LD_SONAME_FLAGS=-soname,$(LIBSO),-z,defs,-z,relro + +ifeq ($(OS), Darwin) +override CFLAGS += -I/opt/local/include -I../../libsepol/include +override LDFLAGS += -L../../libsepol/src -undefined dynamic_lookup +endif + +override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS) +override LDFLAGS += -L../src +override LDLIBS += -lselinux +PCRE_LDLIBS ?= -lpcre + +ifeq ($(ANDROID_HOST),y) +TARGETS=sefcontext_compile +else +TARGETS=$(patsubst %.c,%,$(sort $(wildcard *.c))) +endif + +sefcontext_compile: LDLIBS += $(PCRE_LDLIBS) ../src/libselinux.a -lsepol + +sefcontext_compile: sefcontext_compile.o ../src/regex.o + +all: $(TARGETS) + +install: all + -mkdir -p $(DESTDIR)$(SBINDIR) + install -m 755 $(TARGETS) $(DESTDIR)$(SBINDIR) + +clean: + rm -f $(TARGETS) *.o *~ + +distclean: clean + +indent: + ../../scripts/Lindent $(wildcard *.[ch]) + +relabel: + diff --git a/utils/avcstat.c b/utils/avcstat.c new file mode 100644 index 0000000..884a10b --- /dev/null +++ b/utils/avcstat.c @@ -0,0 +1,236 @@ +/* + * avcstat - Display SELinux avc statistics. + * + * Copyright (C) 2004 Red Hat, Inc., James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEF_STAT_FILE "/avc/cache_stats" +#define DEF_BUF_SIZE 8192 +#define HEADERS "lookups hits misses allocations reclaims frees" + +struct avc_cache_stats { + unsigned long long lookups; + unsigned long long hits; + unsigned long long misses; + unsigned long long allocations; + unsigned long long reclaims; + unsigned long long frees; +}; + +static int interval; +static int rows; +static char *progname; +static char buf[DEF_BUF_SIZE]; + +/* selinuxfs mount point */ +extern char *selinux_mnt; + +static __attribute__((__format__(printf,1,2),__noreturn__)) void die(const char *msg, ...) +{ + va_list args; + + fputs("ERROR: ", stderr); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + + fputc('\n', stderr); + exit(1); +} + +static void usage(void) +{ + printf("\nUsage: %s [-c] [-f status_file] [interval]\n\n", progname); + printf + ("Display SELinux AVC statistics. If the interval parameter is specified, the\n"); + printf + ("program will loop, displaying updated statistics every \'interval\' seconds.\n"); + printf + ("Relative values are displayed by default. Use the -c option to specify the\n"); + printf + ("display of cumulative values. The -f option specifies the location of the\n"); + printf("AVC statistics file, defaulting to \'%s%s\'.\n\n", selinux_mnt, + DEF_STAT_FILE); +} + +static void set_window_rows(void) +{ + int ret; + struct winsize ws; + + ret = ioctl(fileno(stdout), TIOCGWINSZ, &ws); + if (ret < 0 || ws.ws_row < 3) + ws.ws_row = 24; + rows = ws.ws_row; +} + +static void sighandler(int num) +{ + if (num == SIGWINCH) + set_window_rows(); +} + +int main(int argc, char **argv) +{ + struct avc_cache_stats tot, rel, last; + int fd, i, cumulative = 0; + struct sigaction sa; + char avcstatfile[PATH_MAX]; + snprintf(avcstatfile, sizeof avcstatfile, "%s%s", selinux_mnt, + DEF_STAT_FILE); + progname = basename(argv[0]); + + memset(&last, 0, sizeof(last)); + + while ((i = getopt(argc, argv, "cf:h?-")) != -1) { + switch (i) { + case 'c': + cumulative = 1; + break; + case 'f': + strncpy(avcstatfile, optarg, sizeof(avcstatfile) - 1); + avcstatfile[sizeof(avcstatfile)-1] = '\0'; + break; + case 'h': + case '-': + usage(); + exit(0); + default: + usage(); + die("unrecognized parameter '%c'", i); + } + } + + if (optind < argc) { + char *arg = argv[optind]; + unsigned int n = strtoul(arg, NULL, 10); + + if (errno == ERANGE) { + usage(); + die("invalid interval \'%s\'", arg); + } + if (n == 0) { + usage(); + exit(0); + } + interval = n; + } + + sa.sa_handler = sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + + i = sigaction(SIGWINCH, &sa, NULL); + if (i < 0) + die("sigaction"); + + set_window_rows(); + fd = open(avcstatfile, O_RDONLY); + if (fd < 0) + die("open: \'%s\'", avcstatfile); + + for (i = 0;; i++) { + char *line; + ssize_t ret, parsed = 0; + + memset(buf, 0, DEF_BUF_SIZE); + ret = read(fd, buf, DEF_BUF_SIZE-1); + if (ret < 0) + die("read"); + + if (ret == 0) + die("read: \'%s\': unexpected end of file", + avcstatfile); + + line = strtok(buf, "\n"); + if (!line) + die("unable to parse \'%s\': end of line not found", + avcstatfile); + + if (strcmp(line, HEADERS)) + die("unable to parse \'%s\': invalid headers", + avcstatfile); + + if (!i || !(i % (rows - 2))) + printf("%10s %10s %10s %10s %10s %10s\n", "lookups", + "hits", "misses", "allocs", "reclaims", "frees"); + + memset(&tot, 0, sizeof(tot)); + + while ((line = strtok(NULL, "\n"))) { + struct avc_cache_stats tmp; + + ret = sscanf(line, "%llu %llu %llu %llu %llu %llu", + &tmp.lookups, + &tmp.hits, + &tmp.misses, + &tmp.allocations, + &tmp.reclaims, &tmp.frees); + if (ret != 6) + die("unable to parse \'%s\': scan error", + avcstatfile); + + tot.lookups += tmp.lookups; + tot.hits += tmp.hits; + tot.misses += tmp.misses; + tot.allocations += tmp.allocations; + tot.reclaims += tmp.reclaims; + tot.frees += tmp.frees; + parsed = 1; + } + + if (!parsed) + die("unable to parse \'%s\': no data", avcstatfile); + + if (cumulative || !i) + printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", + tot.lookups, tot.hits, tot.misses, + tot.allocations, tot.reclaims, tot.frees); + else { + rel.lookups = tot.lookups - last.lookups; + rel.hits = tot.hits - last.hits; + rel.misses = tot.misses - last.misses; + rel.allocations = tot.allocations - last.allocations; + rel.reclaims = tot.reclaims - last.reclaims; + rel.frees = tot.frees - last.frees; + printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", + rel.lookups, rel.hits, rel.misses, + rel.allocations, rel.reclaims, rel.frees); + } + + if (!interval) + break; + + memcpy(&last, &tot, sizeof(last)); + sleep(interval); + + ret = lseek(fd, 0, 0); + if (ret < 0) + die("lseek"); + } + + close(fd); + return 0; +} diff --git a/utils/compute_av.c b/utils/compute_av.c new file mode 100644 index 0000000..574fa6e --- /dev/null +++ b/utils/compute_av.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + struct av_decision avd; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); + exit(2); + } + + ret = security_compute_av(argv[1], argv[2], tclass, 1, &avd); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_av failed\n", argv[0]); + exit(3); + } + + printf("allowed="); + print_access_vector(tclass, avd.allowed); + printf("\n"); + + if (avd.decided != ~0U) { + printf("decided="); + print_access_vector(tclass, avd.decided); + printf("\n"); + } + + if (avd.auditallow) { + printf("auditallow="); + print_access_vector(tclass, avd.auditallow); + printf("\n"); + } + + if (avd.auditdeny != ~0U) { + printf("auditdeny"); + print_access_vector(tclass, avd.auditdeny); + printf("\n"); + } + + exit(0); +} diff --git a/utils/compute_create.c b/utils/compute_create.c new file mode 100644 index 0000000..4abc29f --- /dev/null +++ b/utils/compute_create.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "Invalid class '%s'\n", argv[3]); + exit(2); + } + + ret = security_compute_create(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_create failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +} diff --git a/utils/compute_member.c b/utils/compute_member.c new file mode 100644 index 0000000..14edd45 --- /dev/null +++ b/utils/compute_member.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "Invalid class '%s'\n", argv[3]); + exit(2); + } + + ret = security_compute_member(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_member failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +} diff --git a/utils/compute_relabel.c b/utils/compute_relabel.c new file mode 100644 index 0000000..970750e --- /dev/null +++ b/utils/compute_relabel.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + security_class_t tclass; + int ret; + + if (argc != 4) { + fprintf(stderr, "usage: %s scontext tcontext tclass\n", + argv[0]); + exit(1); + } + + tclass = string_to_security_class(argv[3]); + if (!tclass) { + fprintf(stderr, "%s: invalid class '%s'\n", argv[0], argv[3]); + exit(2); + } + + ret = security_compute_relabel(argv[1], argv[2], tclass, &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_relabel failed\n", + argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +} diff --git a/utils/compute_user.c b/utils/compute_user.c new file mode 100644 index 0000000..cae62b2 --- /dev/null +++ b/utils/compute_user.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char **buf, **ptr; + int ret; + + if (argc != 3) { + fprintf(stderr, "usage: %s context user\n", argv[0]); + exit(1); + } + + ret = security_compute_user(argv[1], argv[2], &buf); + if (ret < 0) { + fprintf(stderr, "%s: security_compute_user(%s,%s) failed\n", + argv[0], argv[1], argv[2]); + exit(2); + } + + if (!buf[0]) { + printf("none\n"); + exit(0); + } + + for (ptr = buf; *ptr; ptr++) { + printf("%s\n", *ptr); + } + freeconary(buf); + exit(0); +} diff --git a/utils/getconlist.c b/utils/getconlist.c new file mode 100644 index 0000000..5ac0ca8 --- /dev/null +++ b/utils/getconlist.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s [-l level] user [context]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +int main(int argc, char **argv) +{ + char **list, *cur_context = NULL; + char *user = NULL, *level = NULL; + int ret, i, opt; + + while ((opt = getopt(argc, argv, "l:")) > 0) { + switch (opt) { + case 'l': + level = strdup(optarg); + break; + default: + usage(argv[0], "invalid option", 1); + } + } + + if (((argc - optind) < 1) || ((argc - optind) > 2)) + usage(argv[0], "invalid number of arguments", 2); + + /* If selinux isn't available, bail out. */ + if (!is_selinux_enabled()) { + fprintf(stderr, + "getconlist may be used only on a SELinux kernel.\n"); + free(level); + return 1; + } + + user = argv[optind]; + + /* If a context wasn't passed, use the current context. */ + if (((argc - optind) < 2)) { + if (getcon(&cur_context) < 0) { + fprintf(stderr, "Couldn't get current context.\n"); + free(level); + return 2; + } + } else + cur_context = argv[optind + 1]; + + /* Get the list and print it */ + if (level) + ret = + get_ordered_context_list_with_level(user, level, + cur_context, &list); + else + ret = get_ordered_context_list(user, cur_context, &list); + if (ret != -1) { + for (i = 0; list[i]; i++) + puts(list[i]); + freeconary(list); + } + + free(level); + + return 0; +} diff --git a/utils/getdefaultcon.c b/utils/getdefaultcon.c new file mode 100644 index 0000000..96a5a8c --- /dev/null +++ b/utils/getdefaultcon.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s [-l level] [-s service] user [fromcon]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +int main(int argc, char **argv) +{ + char * usercon = NULL, *cur_context = NULL; + char *user = NULL, *level = NULL, *role=NULL, *seuser=NULL, *dlevel=NULL; + char *service = NULL; + int ret, opt; + int verbose = 0; + + while ((opt = getopt(argc, argv, "l:r:s:v")) > 0) { + switch (opt) { + case 'l': + level = strdup(optarg); + break; + case 'r': + role = strdup(optarg); + break; + case 's': + service = strdup(optarg); + break; + case 'v': + verbose = 1; + break; + default: + usage(argv[0], "invalid option", 1); + } + } + + if (((argc - optind) < 1) || ((argc - optind) > 2)) + usage(argv[0], "invalid number of arguments", 2); + + /* If selinux isn't available, bail out. */ + if (!is_selinux_enabled()) { + fprintf(stderr, + "%s may be used only on a SELinux kernel.\n", argv[0]); + return 1; + } + + user = argv[optind]; + + /* If a context wasn't passed, use the current context. */ + if (((argc - optind) < 2)) { + if (getcon(&cur_context) < 0) { + fprintf(stderr, "Couldn't get current context.\n"); + return 2; + } + } else + cur_context = argv[optind + 1]; + + if ((ret = getseuser(user, service, &seuser, &dlevel)) == 0) { + if (! level) level=dlevel; + if (role != NULL && role[0]) + ret=get_default_context_with_rolelevel(seuser, role, level,cur_context,&usercon); + else + ret=get_default_context_with_level(seuser, level, cur_context,&usercon); + } + if (ret < 0) + perror(argv[0]); + else { + if (verbose) { + printf("%s: %s from %s %s %s %s -> %s\n", argv[0], user, cur_context, seuser, role, level, usercon); + } else { + printf("%s\n", usercon); + } + } + + free(role); + free(seuser); + if (level != dlevel) free(level); + free(dlevel); + free(usercon); + + return ret >= 0; +} diff --git a/utils/getenforce.c b/utils/getenforce.c new file mode 100644 index 0000000..e5d19c5 --- /dev/null +++ b/utils/getenforce.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main(int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused))) +{ + int rc; + + rc = is_selinux_enabled(); + if (rc < 0) { + fputs("getenforce: is_selinux_enabled() failed", stderr); + return 2; + } + if (rc == 1) { + rc = security_getenforce(); + if (rc < 0) { + fputs("getenforce: getenforce() failed", stderr); + return 2; + } + + if (rc) + puts("Enforcing"); + else + puts("Permissive"); + } else { + puts("Disabled"); + } + + return 0; +} diff --git a/utils/getfilecon.c b/utils/getfilecon.c new file mode 100644 index 0000000..a7a51ab --- /dev/null +++ b/utils/getfilecon.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + int rc, i; + + if (argc < 2) { + fprintf(stderr, "usage: %s path...\n", argv[0]); + exit(1); + } + + for (i = 1; i < argc; i++) { + rc = getfilecon(argv[i], &buf); + if (rc < 0) { + fprintf(stderr, "%s: getfilecon(%s) failed\n", argv[0], + argv[i]); + exit(2); + } + printf("%s\t%s\n", argv[i], buf); + freecon(buf); + } + exit(0); +} diff --git a/utils/getpidcon.c b/utils/getpidcon.c new file mode 100644 index 0000000..3df0da1 --- /dev/null +++ b/utils/getpidcon.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + pid_t pid; + char *buf; + int rc; + + if (argc != 2) { + fprintf(stderr, "usage: %s pid\n", argv[0]); + exit(1); + } + + if (sscanf(argv[1], "%d", &pid) != 1) { + fprintf(stderr, "%s: invalid pid %s\n", argv[0], argv[1]); + exit(2); + } + + rc = getpidcon(pid, &buf); + if (rc < 0) { + fprintf(stderr, "%s: getpidcon() failed\n", argv[0]); + exit(3); + } + + printf("%s\n", buf); + freecon(buf); + exit(0); +} diff --git a/utils/getsebool.c b/utils/getsebool.c new file mode 100644 index 0000000..3699453 --- /dev/null +++ b/utils/getsebool.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, "usage: %s -a or %s boolean...\n", progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int i, get_all = 0, rc = 0, active, pending, len = 0, opt; + char **names = NULL; + + while ((opt = getopt(argc, argv, "a")) > 0) { + switch (opt) { + case 'a': + if (argc > 2) + usage(argv[0]); + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", + argv[0]); + return 1; + } + errno = 0; + rc = security_get_boolean_names(&names, &len); + if (rc) { + fprintf(stderr, + "%s: Unable to get boolean names: %s\n", + argv[0], strerror(errno)); + return 1; + } + if (!len) { + printf("No booleans\n"); + return 0; + } + get_all = 1; + break; + default: + usage(argv[0]); + } + } + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + + if (!len) { + if (argc < 2) + usage(argv[0]); + len = argc - 1; + names = calloc(len, sizeof(char *)); + if (!names) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + return 2; + } + for (i = 0; i < len; i++) { + names[i] = strdup(argv[i + 1]); + if (!names[i]) { + fprintf(stderr, "%s: out of memory\n", + argv[0]); + rc = 2; + goto out; + } + } + } + + for (i = 0; i < len; i++) { + active = security_get_boolean_active(names[i]); + if (active < 0) { + if (get_all && errno == EACCES) + continue; + fprintf(stderr, "Error getting active value for %s\n", + names[i]); + rc = -1; + goto out; + } + pending = security_get_boolean_pending(names[i]); + if (pending < 0) { + fprintf(stderr, "Error getting pending value for %s\n", + names[i]); + rc = -1; + goto out; + } + char *alt_name = selinux_boolean_sub(names[i]); + if (! alt_name) { + perror("Out of memory\n"); + rc = -1; + goto out; + } + + if (pending != active) { + printf("%s --> %s pending: %s\n", alt_name, + (active ? "on" : "off"), + (pending ? "on" : "off")); + } else { + printf("%s --> %s\n", alt_name, + (active ? "on" : "off")); + } + free(alt_name); + } + + out: + for (i = 0; i < len; i++) + free(names[i]); + free(names); + return rc; +} diff --git a/utils/getseuser.c b/utils/getseuser.c new file mode 100644 index 0000000..c33a4ad --- /dev/null +++ b/utils/getseuser.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *seuser = NULL, *level = NULL; + char **contextlist; + int rc, n, i; + + if (argc != 3) { + fprintf(stderr, "usage: %s linuxuser fromcon\n", argv[0]); + exit(1); + } + + rc = getseuserbyname(argv[1], &seuser, &level); + if (rc) { + fprintf(stderr, "getseuserbyname failed: %s\n", + strerror(errno)); + exit(2); + } + printf("seuser: %s, level %s\n", seuser, level); + n = get_ordered_context_list_with_level(seuser, level, argv[2], + &contextlist); + if (n <= 0) { + fprintf(stderr, + "get_ordered_context_list_with_level failed: %s\n", + strerror(errno)); + exit(3); + } + free(seuser); + free(level); + for (i = 0; i < n; i++) + printf("Context %d\t%s\n", i, contextlist[i]); + freeconary(contextlist); + exit(0); +} diff --git a/utils/matchpathcon.c b/utils/matchpathcon.c new file mode 100644 index 0000000..9756d7d --- /dev/null +++ b/utils/matchpathcon.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-V] [-N] [-n] [-m type] [-f file_contexts_file] [-p prefix] [-P policy_root_path] filepath...\n", + progname); + exit(1); +} + +static int printmatchpathcon(const char *path, int header, int mode) +{ + char *buf; + int rc = matchpathcon(path, mode, &buf); + if (rc < 0) { + if (errno == ENOENT) { + buf=strdup("<>"); + } else { + fprintf(stderr, "matchpathcon(%s) failed: %s\n", path, + strerror(errno)); + return 1; + } + } + if (header) + printf("%s\t%s\n", path, buf); + else + printf("%s\n", buf); + + freecon(buf); + return 0; +} + +static mode_t string_to_mode(char *s) +{ + switch (s[0]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case 'f': + return S_IFREG; + default: + return -1; + }; + return -1; +} + +int main(int argc, char **argv) +{ + int i, init = 0, force_mode = 0; + int header = 1, opt; + int verify = 0; + int notrans = 0; + int error = 0; + int quiet = 0; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "m:Nnf:P:p:Vq")) > 0) { + switch (opt) { + case 'n': + header = 0; + break; + case 'm': + force_mode = string_to_mode(optarg); + if (force_mode < 0) { + fprintf(stderr, "%s: mode %s is invalid\n", argv[0], optarg); + exit(1); + } + break; + case 'V': + verify = 1; + break; + case 'N': + notrans = 1; + set_matchpathcon_flags(MATCHPATHCON_NOTRANS); + break; + case 'f': + if (init) { + fprintf(stderr, + "%s: -f and -p are exclusive\n", + argv[0]); + exit(1); + } + init = 1; + if (matchpathcon_init(optarg)) { + fprintf(stderr, + "Error while processing %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'P': + if (selinux_set_policy_root(optarg) < 0 ) { + fprintf(stderr, + "Error setting policy root %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'p': + if (init) { + fprintf(stderr, + "%s: -f and -p are exclusive\n", + argv[0]); + exit(1); + } + init = 1; + if (matchpathcon_init_prefix(NULL, optarg)) { + fprintf(stderr, + "Error while processing %s: %s\n", + optarg, + errno ? strerror(errno) : "invalid"); + exit(1); + } + break; + case 'q': + quiet = 1; + break; + default: + usage(argv[0]); + } + } + for (i = optind; i < argc; i++) { + int rc, mode = 0; + struct stat buf; + char *path = argv[i]; + int len = strlen(path); + if (len > 1 && path[len - 1 ] == '/') + path[len - 1 ] = '\0'; + + if (lstat(path, &buf) == 0) + mode = buf.st_mode; + if (force_mode) + mode = force_mode; + + if (verify) { + rc = selinux_file_context_verify(path, mode); + + if (quiet) { + if (rc == 1) + continue; + else + exit(1); + } + + if (rc == -1) { + printf("%s error: %s\n", path, strerror(errno)); + exit(1); + } else if (rc == 1) { + printf("%s verified.\n", path); + } else { + char * con; + error = 1; + if (notrans) + rc = lgetfilecon_raw(path, &con); + else + rc = lgetfilecon(path, &con); + + if (rc >= 0) { + printf("%s has context %s, should be ", + path, con); + printmatchpathcon(path, 0, mode); + freecon(con); + } else { + printf + ("actual context unknown: %s, should be ", + strerror(errno)); + printmatchpathcon(path, 0, mode); + } + } + } else { + error |= printmatchpathcon(path, header, mode); + } + } + matchpathcon_fini(); + return error; +} diff --git a/utils/policyvers.c b/utils/policyvers.c new file mode 100644 index 0000000..0309d7d --- /dev/null +++ b/utils/policyvers.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int main(int argc __attribute__ ((unused)), char **argv) +{ + int rc; + + rc = security_policyvers(); + if (rc < 0) { + fprintf(stderr, "%s: policyvers() failed\n", argv[0]); + exit(2); + } + + printf("%d\n", rc); + exit(0); +} diff --git a/utils/sefcontext_compile.c b/utils/sefcontext_compile.c new file mode 100644 index 0000000..54600e2 --- /dev/null +++ b/utils/sefcontext_compile.c @@ -0,0 +1,463 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/label_file.h" +#include "../src/regex.h" + +const char *policy_file; +static int ctx_err; + +static int validate_context(char **ctxp) +{ + char *ctx = *ctxp; + + if (policy_file && sepol_check_context(ctx) < 0) { + ctx_err = -1; + return ctx_err; + } + + return 0; +} + +static int process_file(struct selabel_handle *rec, const char *filename) +{ + unsigned int line_num; + int rc; + char *line_buf = NULL; + size_t line_len = 0; + FILE *context_file; + const char *prefix = NULL; + + context_file = fopen(filename, "r"); + if (!context_file) { + fprintf(stderr, "Error opening %s: %s\n", + filename, strerror(errno)); + return -1; + } + + line_num = 0; + rc = 0; + while (getline(&line_buf, &line_len, context_file) > 0) { + rc = process_line(rec, filename, prefix, line_buf, ++line_num); + if (rc || ctx_err) { + /* With -p option need to check and fail if ctx err as + * process_line() context validation on Linux does not + * return an error, but does print the error line to + * stderr. Android will set both to error and print + * the error line. */ + rc = -1; + goto out; + } + } +out: + free(line_buf); + fclose(context_file); + return rc; +} + +/* + * File Format + * + * u32 - magic number + * u32 - version + * u32 - length of pcre version EXCLUDING nul + * char - pcre version string EXCLUDING nul + * u32 - number of stems + * ** Stems + * u32 - length of stem EXCLUDING nul + * char - stem char array INCLUDING nul + * u32 - number of regexs + * ** Regexes + * u32 - length of upcoming context INCLUDING nul + * char - char array of the raw context + * u32 - length of the upcoming regex_str + * char - char array of the original regex string including the stem. + * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE + * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS + * s32 - stemid associated with the regex + * u32 - spec has meta characters + * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN + * u32 - data length of the pcre regex + * char - a bufer holding the raw pcre regex info + * u32 - data length of the pcre regex study daya + * char - a buffer holding the raw pcre regex study data + */ +static int write_binary_file(struct saved_data *data, int fd, + int do_write_precompregex) +{ + struct spec *specs = data->spec_arr; + FILE *bin_file; + size_t len; + uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT; + uint32_t section_len; + uint32_t i; + int rc; + const char *reg_version; + const char *reg_arch; + + bin_file = fdopen(fd, "w"); + if (!bin_file) { + perror("fopen output_file"); + exit(EXIT_FAILURE); + } + + /* write some magic number */ + len = fwrite(&magic, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write the version */ + section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* write version of the regex back-end */ + reg_version = regex_version(); + if (!reg_version) + goto err; + section_len = strlen(reg_version); + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + len = fwrite(reg_version, sizeof(char), section_len, bin_file); + if (len != section_len) + goto err; + + /* write regex arch string */ + reg_arch = regex_arch_string(); + if (!reg_arch) + goto err; + section_len = strlen(reg_arch); + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + len = fwrite(reg_arch, sizeof(char), section_len, bin_file); + if (len != section_len) + goto err; + + /* write the number of stems coming */ + section_len = data->num_stems; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + for (i = 0; i < section_len; i++) { + char *stem = data->stem_arr[i].buf; + uint32_t stem_len = data->stem_arr[i].len; + + /* write the strlen (aka no nul) */ + len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* include the nul in the file */ + stem_len += 1; + len = fwrite(stem, sizeof(char), stem_len, bin_file); + if (len != stem_len) + goto err; + } + + /* write the number of regexes coming */ + section_len = data->nspec; + len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + for (i = 0; i < section_len; i++) { + char *context = specs[i].lr.ctx_raw; + char *regex_str = specs[i].regex_str; + mode_t mode = specs[i].mode; + size_t prefix_len = specs[i].prefix_len; + int32_t stem_id = specs[i].stem_id; + struct regex_data *re = specs[i].regex; + uint32_t to_write; + + /* length of the context string (including nul) */ + to_write = strlen(context) + 1; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* original context strin (including nul) */ + len = fwrite(context, sizeof(char), to_write, bin_file); + if (len != to_write) + goto err; + + /* length of the original regex string (including nul) */ + to_write = strlen(regex_str) + 1; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* original regex string */ + len = fwrite(regex_str, sizeof(char), to_write, bin_file); + if (len != to_write) + goto err; + + /* binary F_MODE bits */ + to_write = mode; + len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); + if (len != 1) + goto err; + + /* stem for this regex (could be -1) */ + len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file); + if (len != 1) + goto err; + + /* does this spec have a metaChar? */ + to_write = specs[i].hasMetaChars; + len = fwrite(&to_write, sizeof(to_write), 1, bin_file); + if (len != 1) + goto err; + + /* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */ + to_write = prefix_len; + len = fwrite(&to_write, sizeof(to_write), 1, bin_file); + if (len != 1) + goto err; + + /* Write regex related data */ + rc = regex_writef(re, bin_file, do_write_precompregex); + if (rc < 0) + goto err; + } + + rc = 0; +out: + fclose(bin_file); + return rc; +err: + rc = -1; + goto out; +} + +static void free_specs(struct saved_data *data) +{ + struct spec *specs = data->spec_arr; + unsigned int num_entries = data->nspec; + unsigned int i; + + for (i = 0; i < num_entries; i++) { + free(specs[i].lr.ctx_raw); + free(specs[i].lr.ctx_trans); + free(specs[i].regex_str); + free(specs[i].type_str); + regex_data_free(specs[i].regex); + } + free(specs); + + num_entries = data->num_stems; + for (i = 0; i < num_entries; i++) + free(data->stem_arr[i].buf); + free(data->stem_arr); + + memset(data, 0, sizeof(*data)); +} + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-o out_file] [-p policy_file] fc_file\n" + "Where:\n\t" + "-o Optional file name of the PCRE formatted binary\n\t" + " file to be output. If not specified the default\n\t" + " will be fc_file with the .bin suffix appended.\n\t" + "-p Optional binary policy file that will be used to\n\t" + " validate contexts defined in the fc_file.\n\t" + "-r Omit precompiled regular expressions from the output.\n\t" + " (PCRE2 only. Compiled PCRE2 regular expressions are\n\t" + " not portable across architectures. Use this flag\n\t" + " if you know that you build for an incompatible\n\t" + " architecture to save space. When linked against\n\t" + " PCRE1 this flag is ignored.)\n\t" + "-i Print regular expression info end exit. That is, back\n\t" + " end version and architecture identifier.\n\t" + " Arch identifier format (PCRE2):\n\t" + " --, e.g.,\n\t" + " \"8-8-el\" for x86_64.\n\t" + "fc_file The text based file contexts file to be processed.\n", + progname); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + const char *path = NULL; + const char *out_file = NULL; + int do_write_precompregex = 1; + char stack_path[PATH_MAX + 1]; + char *tmp = NULL; + int fd, rc, opt; + FILE *policy_fp = NULL; + struct stat buf; + struct selabel_handle *rec = NULL; + struct saved_data *data = NULL; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "io:p:r")) > 0) { + switch (opt) { + case 'o': + out_file = optarg; + break; + case 'p': + policy_file = optarg; + break; + case 'r': + do_write_precompregex = 0; + break; + case 'i': + printf("%s (%s)\n", regex_version(), + regex_arch_string()); + return 0; + default: + usage(argv[0]); + } + } + + if (optind >= argc) + usage(argv[0]); + + path = argv[optind]; + if (stat(path, &buf) < 0) { + fprintf(stderr, "%s: could not stat: %s: %s\n", argv[0], path, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Open binary policy if supplied. */ + if (policy_file) { + policy_fp = fopen(policy_file, "r"); + + if (!policy_fp) { + fprintf(stderr, "%s: failed to open %s: %s\n", + argv[0], policy_file, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (sepol_set_policydb_from_file(policy_fp) < 0) { + fprintf(stderr, "%s: failed to load policy from %s\n", + argv[0], policy_file); + fclose(policy_fp); + exit(EXIT_FAILURE); + } + } + + /* Generate dummy handle for process_line() function */ + rec = (struct selabel_handle *)calloc(1, sizeof(*rec)); + if (!rec) { + fprintf(stderr, "%s: calloc failed: %s\n", argv[0], strerror(errno)); + if (policy_fp) + fclose(policy_fp); + exit(EXIT_FAILURE); + } + rec->backend = SELABEL_CTX_FILE; + + /* Need to set validation on to get the bin file generated by the + * process_line function, however as the bin file being generated + * may not be related to the currently loaded policy (that it + * would be validated against), then set callback to ignore any + * validation - unless the -p option is used in which case if an + * error is detected, the process will be aborted. */ + rec->validating = 1; + selinux_set_callback(SELINUX_CB_VALIDATE, + (union selinux_callback)&validate_context); + + data = (struct saved_data *)calloc(1, sizeof(*data)); + if (!data) { + fprintf(stderr, "%s: calloc failed: %s\n", argv[0], strerror(errno)); + free(rec); + if (policy_fp) + fclose(policy_fp); + exit(EXIT_FAILURE); + } + + rec->data = data; + + rc = process_file(rec, path); + if (rc < 0) { + fprintf(stderr, "%s: process_file failed\n", argv[0]); + goto err; + } + + rc = sort_specs(data); + if (rc) { + fprintf(stderr, "%s: sort_specs failed\n", argv[0]); + goto err; + } + + if (out_file) + rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file); + else + rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path); + + if (rc < 0 || rc >= (int)sizeof(stack_path)) { + fprintf(stderr, "%s: snprintf failed\n", argv[0]); + goto err; + } + + tmp = malloc(strlen(stack_path) + 7); + if (!tmp) { + fprintf(stderr, "%s: malloc failed: %s\n", argv[0], strerror(errno)); + goto err; + } + + rc = sprintf(tmp, "%sXXXXXX", stack_path); + if (rc < 0) { + fprintf(stderr, "%s: sprintf failed\n", argv[0]); + goto err; + } + + fd = mkstemp(tmp); + if (fd < 0) { + fprintf(stderr, "%s: mkstemp %s failed: %s\n", argv[0], tmp, strerror(errno)); + goto err; + } + + rc = fchmod(fd, buf.st_mode); + if (rc < 0) { + fprintf(stderr, "%s: fchmod %s failed: %s\n", argv[0], tmp, strerror(errno)); + goto err_unlink; + } + + rc = write_binary_file(data, fd, do_write_precompregex); + if (rc < 0) { + fprintf(stderr, "%s: write_binary_file %s failed\n", argv[0], tmp); + goto err_unlink; + } + + rc = rename(tmp, stack_path); + if (rc < 0) { + fprintf(stderr, "%s: rename %s -> %s failed: %s\n", argv[0], tmp, stack_path, strerror(errno)); + goto err_unlink; + } + + rc = 0; +out: + if (policy_fp) + fclose(policy_fp); + + free_specs(data); + free(rec); + free(data); + free(tmp); + return rc; + +err_unlink: + unlink(tmp); +err: + rc = -1; + goto out; +} diff --git a/utils/selabel_digest.c b/utils/selabel_digest.c new file mode 100644 index 0000000..49408a0 --- /dev/null +++ b/utils/selabel_digest.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include +#include + +static size_t digest_len; + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n" + "Where:\n\t" + "-b The backend - \"file\", \"media\", \"x\", \"db\" or " + "\"prop\"\n\t" + "-v Run \"cat | openssl dgst -sha1 -hex\"\n\t" + " on the list of specfiles to compare the SHA1 digests.\n\t" + "-B Use base specfiles only (valid for \"-b file\" only).\n\t" + "-i Do not request a digest.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\n", + progname); + exit(1); +} + +static int run_check_digest(char *cmd, char *selabel_digest) +{ + FILE *fp; + char files_digest[128]; + char *files_ptr; + int rc = 0; + + fp = popen(cmd, "r"); + if (!fp) { + printf("Failed to run command line\n"); + return -1; + } + + /* Only expect one line "(stdin)= x.." so read and find first space */ + while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL) + ; + + files_ptr = strstr(files_digest, " "); + + rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2); + if (rc) { + printf("Failed validation:\n\tselabel_digest: %s\n\t" + "files_digest: %s\n", + selabel_digest, files_ptr + 1); + } else { + printf("Passed validation - digest: %s\n", selabel_digest); + } + + pclose(fp); + return rc; +} + +int main(int argc, char **argv) +{ + int backend = 0, rc, opt, validate = 0; + char *baseonly = NULL, *file = NULL, *digest = (char *)1; + char **specfiles = NULL; + unsigned char *sha1_digest = NULL; + size_t i, num_specfiles; + + char cmd_buf[4096]; + char *cmd_ptr; + char *sha1_buf; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_BASEONLY, baseonly }, + { SELABEL_OPT_DIGEST, digest } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) { + switch (opt) { + case 'b': + if (!strcasecmp(optarg, "file")) { + backend = SELABEL_CTX_FILE; + } else if (!strcmp(optarg, "media")) { + backend = SELABEL_CTX_MEDIA; + } else if (!strcmp(optarg, "x")) { + backend = SELABEL_CTX_X; + } else if (!strcmp(optarg, "db")) { + backend = SELABEL_CTX_DB; + } else if (!strcmp(optarg, "prop")) { + backend = SELABEL_CTX_ANDROID_PROP; + } else if (!strcmp(optarg, "service")) { + backend = SELABEL_CTX_ANDROID_SERVICE; + } else { + fprintf(stderr, "Unknown backend: %s\n", + optarg); + usage(argv[0]); + } + break; + case 'B': + baseonly = (char *)1; + break; + case 'v': + validate = 1; + break; + case 'i': + digest = NULL; + break; + case 'f': + file = optarg; + break; + default: + usage(argv[0]); + } + } + + memset(cmd_buf, 0, sizeof(cmd_buf)); + + selabel_option[0].value = file; + selabel_option[1].value = baseonly; + selabel_option[2].value = digest; + + hnd = selabel_open(backend, selabel_option, 3); + if (!hnd) { + switch (errno) { + case EOVERFLOW: + fprintf(stderr, "ERROR Number of specfiles or specfile" + " buffer caused an overflow.\n"); + break; + default: + fprintf(stderr, "ERROR: selabel_open: %s\n", + strerror(errno)); + } + return -1; + } + + rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles, + &num_specfiles); + + if (rc) { + switch (errno) { + case EINVAL: + fprintf(stderr, "No digest available.\n"); + break; + default: + fprintf(stderr, "selabel_digest ERROR: %s\n", + strerror(errno)); + } + goto err; + } + + sha1_buf = malloc(digest_len * 2 + 1); + if (!sha1_buf) { + fprintf(stderr, "Could not malloc buffer ERROR: %s\n", + strerror(errno)); + rc = -1; + goto err; + } + + printf("SHA1 digest: "); + for (i = 0; i < digest_len; i++) + sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]); + + printf("%s\n", sha1_buf); + printf("calculated using the following specfile(s):\n"); + + if (specfiles) { + cmd_ptr = &cmd_buf[0]; + sprintf(cmd_ptr, "/usr/bin/cat "); + cmd_ptr = &cmd_buf[0] + strlen(cmd_buf); + + for (i = 0; i < num_specfiles; i++) { + sprintf(cmd_ptr, "%s ", specfiles[i]); + cmd_ptr += strlen(specfiles[i]) + 1; + printf("%s\n", specfiles[i]); + } + sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex"); + + if (validate) + rc = run_check_digest(cmd_buf, sha1_buf); + } + + free(sha1_buf); +err: + selabel_close(hnd); + return rc; +} diff --git a/utils/selabel_lookup.c b/utils/selabel_lookup.c new file mode 100644 index 0000000..1aef64d --- /dev/null +++ b/utils/selabel_lookup.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s -b backend [-v] [-r] -k key [-t type] [-f file]\n\n" + "Where:\n\t" + "-b The backend - \"file\", \"media\", \"x\", \"db\" or " + "\"prop\"\n\t" + "-v Validate entries against loaded policy.\n\t" + "-r Use \"raw\" function.\n\t" + "-k Lookup key - Depends on backend.\n\t" + "-t Lookup type - Optional as depends on backend.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\n" + "Examples:\n\t" + "%s -v -b file -k /run -t 0\n\t" + " lookup with validation against the loaded policy, the\n\t" + " \"file\" backend for path \"/run\" with mode = 0\n\t" + "%s -r -b x -t 4 -k X11:ButtonPress\n\t" + " lookup_raw the \"X\" backend for type SELABEL_X_EVENT\n\t" + " using key \"X11:ButtonPress\"\n\n", + progname, progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int raw = 0, type = 0, backend = 0, rc, opt; + char *validate = NULL, *key = NULL, *context = NULL, *file = NULL; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "b:f:vrk:t:")) > 0) { + switch (opt) { + case 'b': + if (!strcasecmp(optarg, "file")) { + backend = SELABEL_CTX_FILE; + } else if (!strcmp(optarg, "media")) { + backend = SELABEL_CTX_MEDIA; + } else if (!strcmp(optarg, "x")) { + backend = SELABEL_CTX_X; + } else if (!strcmp(optarg, "db")) { + backend = SELABEL_CTX_DB; + } else if (!strcmp(optarg, "prop")) { + backend = SELABEL_CTX_ANDROID_PROP; + } else if (!strcmp(optarg, "service")) { + backend = SELABEL_CTX_ANDROID_SERVICE; + } else { + fprintf(stderr, "Unknown backend: %s\n", + optarg); + usage(argv[0]); + } + break; + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'r': + raw = 1; + break; + case 'k': + key = optarg; + break; + case 't': + type = atoi(optarg); + break; + default: + usage(argv[0]); + } + } + + selabel_option[0].value = file; + selabel_option[1].value = validate; + + hnd = selabel_open(backend, selabel_option, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + return -1; + } + + switch (raw) { + case 1: + rc = selabel_lookup_raw(hnd, &context, key, type); + break; + default: + rc = selabel_lookup(hnd, &context, key, type); + } + selabel_close(hnd); + + if (rc) { + switch (errno) { + case ENOENT: + fprintf(stderr, "ERROR: selabel_lookup failed to " + "find a valid context.\n"); + break; + case EINVAL: + fprintf(stderr, "ERROR: selabel_lookup failed to " + "validate context, or key / type are " + "invalid.\n"); + break; + default: + fprintf(stderr, "selabel_lookup ERROR: %s\n", + strerror(errno)); + } + } else { + printf("Default context: %s\n", context); + freecon(context); + } + + return rc; +} diff --git a/utils/selabel_lookup_best_match.c b/utils/selabel_lookup_best_match.c new file mode 100644 index 0000000..6a71742 --- /dev/null +++ b/utils/selabel_lookup_best_match.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-v] [-r] -p path [-m mode] [-f file] [link...]\n\n" + "Where:\n\t" + "-v Validate file_contxts entries against loaded policy.\n\t" + "-r Use \"raw\" function.\n\t" + "-p Path to check for best match using the link(s) provided.\n\t" + "-m Optional mode (b, c, d, p, l, s or f) Defaults to 0.\n\t" + "-f Optional file containing the specs (defaults to\n\t" + " those used by loaded policy).\n\t" + "link Zero or more links to check against, the order of\n\t" + " precedence for best match is:\n\t\t" + " 1) An exact match for the real path (if no links), or\n\t\t" + " 2) An exact match for any of the links (aliases), or\n\t\t" + " 3) The longest fixed prefix match.\n\n" + "Example:\n\t" + "%s -p /dev/initctl /run/systemd/initctl/fifo\n\t" + " Find best matching context for the specified path using one link.\n\n", + progname, progname); + exit(1); +} + +static mode_t string_to_mode(char *s) +{ + switch (s[0]) { + case 'b': + return S_IFBLK; + case 'c': + return S_IFCHR; + case 'd': + return S_IFDIR; + case 'p': + return S_IFIFO; + case 'l': + return S_IFLNK; + case 's': + return S_IFSOCK; + case 'f': + return S_IFREG; + }; + return 0; +} + +int main(int argc, char **argv) +{ + int raw = 0, mode = 0, rc, opt, i, num_links, string_len; + char *validate = NULL, *path = NULL, *context = NULL, *file = NULL; + char **links = NULL; + + struct selabel_handle *hnd; + struct selinux_opt options[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 3) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "f:vrp:m:")) > 0) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'r': + raw = 1; + break; + case 'p': + path = optarg; + break; + case 'm': + mode = string_to_mode(optarg); + break; + default: + usage(argv[0]); + } + } + + /* Count links */ + for (i = optind, num_links = 0; i < argc; i++, num_links++) + ; + + if (num_links) { + links = calloc(num_links + 1, sizeof(char *)); + + if (!links) { + fprintf(stderr, "ERROR: calloc failed.\n"); + exit(1); + } + + for (i = optind, num_links = 0; i < argc; i++, num_links++) { + string_len = strlen(argv[i]) + 1; + links[num_links] = malloc(string_len); + if (!links[num_links]) { + fprintf(stderr, "ERROR: malloc failed.\n"); + exit(1); + } + strcpy(links[num_links], argv[i]); + } + } + + options[0].value = file; + options[1].value = validate; + + hnd = selabel_open(SELABEL_CTX_FILE, options, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + rc = -1; + goto out; + } + + if (raw) + rc = selabel_lookup_best_match_raw(hnd, &context, path, + (const char **)links, mode); + else + rc = selabel_lookup_best_match(hnd, &context, path, + (const char **)links, mode); + + selabel_close(hnd); + + if (rc) { + switch (errno) { + case ENOENT: + fprintf(stderr, "ERROR: selabel_lookup_best_match " + "failed to find a valid context.\n"); + break; + case EINVAL: + fprintf(stderr, "ERROR: selabel_lookup_best_match " + "failed to validate context, or path / mode " + "are invalid.\n"); + break; + default: + fprintf(stderr, "selabel_lookup_best_match ERROR: " + "%s\n", strerror(errno)); + } + } else { + printf("Best match context: %s\n", context); + freecon(context); + } + +out: + if (links) { + for (i = 0; links[i]; i++) + free(links[i]); + free(links); + } + + return rc; +} diff --git a/utils/selabel_partial_match.c b/utils/selabel_partial_match.c new file mode 100644 index 0000000..c5932cb --- /dev/null +++ b/utils/selabel_partial_match.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -p [-f file]\n\n" + "Where:\n\t" + "-v Validate file_contxts entries against loaded policy.\n\t" + "-p Path to check if a match or partial match is possible\n\t" + " against a regex entry in the file_contexts file.\n\t" + "-f Optional file_contexts file (defaults to current policy).\n\n" + "Example:\n\t" + "%s -p /sys/devices/system/cpu/online\n\t" + " Check if a match or partial match is possible against\n\t" + " the path \"/sys/devices/system/cpu/online\", returning\n\t" + " TRUE or FALSE.\n\n", progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt; + bool partial_match; + char *validate = NULL, *path = NULL, *file = NULL; + + struct selabel_handle *hnd; + struct selinux_opt selabel_option[] = { + { SELABEL_OPT_PATH, file }, + { SELABEL_OPT_VALIDATE, validate } + }; + + if (argc < 2) + usage(argv[0]); + + while ((opt = getopt(argc, argv, "f:vp:")) > 0) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'v': + validate = (char *)1; + break; + case 'p': + path = optarg; + break; + default: + usage(argv[0]); + } + } + + selabel_option[0].value = file; + selabel_option[1].value = validate; + + hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2); + if (!hnd) { + fprintf(stderr, "ERROR: selabel_open - Could not obtain " + "handle.\n"); + return -1; + } + + partial_match = selabel_partial_match(hnd, path); + + printf("Match or Partial match: %s\n", + partial_match == 1 ? "TRUE" : "FALSE"); + + selabel_close(hnd); + return partial_match; +} diff --git a/utils/selinux_check_access.c b/utils/selinux_check_access.c new file mode 100644 index 0000000..6cea40e --- /dev/null +++ b/utils/selinux_check_access.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, "usage: %s [-a auditdata] scon tcon class perm\n" + "\nWhere:\n\t" + "-a Optional information added to audit message.\n", + progname); + exit(1); +} + +static int cb_auditinfo(void *auditdata, + __attribute__((unused))security_class_t class, + char *msgbuf, size_t msgbufsize) +{ + return snprintf(msgbuf, msgbufsize, "%s", (char *)auditdata); +} + +int main(int argc, char **argv) +{ + int opt, rc; + char *audit_msg = NULL; + + while ((opt = getopt(argc, argv, "a:")) != -1) { + switch (opt) { + case 'a': + audit_msg = optarg; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 4) + usage(argv[0]); + + if (audit_msg) + selinux_set_callback(SELINUX_CB_AUDIT, + (union selinux_callback)cb_auditinfo); + + rc = selinux_check_access(argv[optind], argv[optind + 1], + argv[optind + 2], argv[optind + 3], + audit_msg); + if (rc < 0) + perror("selinux_check_access"); + + return rc; +} diff --git a/utils/selinux_check_securetty_context.c b/utils/selinux_check_securetty_context.c new file mode 100644 index 0000000..5581dde --- /dev/null +++ b/utils/selinux_check_securetty_context.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, "usage: %s tty_context...\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int i; + if (argc < 2) + usage(argv[0]); + + for (i = 1; i < argc; i++) { + switch (selinux_check_securetty_context(argv[i])) { + case 0: + printf("%s securetty.\n", argv[i]); + break; + default: + printf("%s not securetty.\n", argv[i]); + break; + } + } + return 0; +} diff --git a/utils/selinuxenabled.c b/utils/selinuxenabled.c new file mode 100644 index 0000000..04ea778 --- /dev/null +++ b/utils/selinuxenabled.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +int main(void) +{ + return !is_selinux_enabled(); +} diff --git a/utils/selinuxexeccon.c b/utils/selinuxexeccon.c new file mode 100644 index 0000000..b50e788 --- /dev/null +++ b/utils/selinuxexeccon.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *name, const char *detail, int rc) +{ + fprintf(stderr, "usage: %s command [ fromcon ]\n", name); + if (detail) + fprintf(stderr, "%s: %s\n", name, detail); + exit(rc); +} + +static char * get_selinux_proc_context(const char *command, char * execcon) { + char * fcon = NULL, *newcon = NULL; + + int ret = getfilecon(command, &fcon); + if (ret < 0) goto err; + ret = security_compute_create(execcon, fcon, string_to_security_class("process"), &newcon); + if (ret < 0) goto err; + +err: + freecon(fcon); + return newcon; +} + +int main(int argc, char **argv) +{ + int ret = -1; + char * proccon = NULL, *con = NULL; + if (argc < 2 || argc > 3) + usage(argv[0], "Invalid number of arguments", -1); + + if (argc == 2) { + if (getcon(&con) < 0) { + perror(argv[0]); + return -1; + } + } else { + con = strdup(argv[2]); + } + + proccon = get_selinux_proc_context(argv[1], con); + if (proccon) { + printf("%s\n", proccon); + ret = 0; + } else { + perror(argv[0]); + } + + free(proccon); + free(con); + return ret; +} diff --git a/utils/setenforce.c b/utils/setenforce.c new file mode 100644 index 0000000..60a20a4 --- /dev/null +++ b/utils/setenforce.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include + +static __attribute__ ((__noreturn__)) void usage(const char *progname) +{ + fprintf(stderr, "usage: %s [ Enforcing | Permissive | 1 | 0 ]\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int rc = 0; + if (argc != 2) { + usage(argv[0]); + } + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + if (strlen(argv[1]) == 1 && (argv[1][0] == '0' || argv[1][0] == '1')) { + rc = security_setenforce(atoi(argv[1])); + } else { + if (strcasecmp(argv[1], "enforcing") == 0) { + rc = security_setenforce(1); + } else if (strcasecmp(argv[1], "permissive") == 0) { + rc = security_setenforce(0); + } else + usage(argv[0]); + } + if (rc < 0) { + fprintf(stderr, "%s: setenforce() failed\n", argv[0]); + return 2; + } + return 0; +} diff --git a/utils/setfilecon.c b/utils/setfilecon.c new file mode 100644 index 0000000..d69af84 --- /dev/null +++ b/utils/setfilecon.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int rc, i; + + if (argc < 3) { + fprintf(stderr, "usage: %s context path...\n", argv[0]); + exit(1); + } + + for (i = 2; i < argc; i++) { + rc = setfilecon(argv[i], argv[1]); + if (rc < 0) { + fprintf(stderr, "%s: setfilecon(%s,%s) failed\n", + argv[0], argv[i], argv[1]); + exit(2); + } + } + exit(0); +} diff --git a/utils/togglesebool.c b/utils/togglesebool.c new file mode 100644 index 0000000..4a7c830 --- /dev/null +++ b/utils/togglesebool.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Attempt to rollback the transaction. No need to check error + codes since this is rolling back something that blew up. */ +static __attribute__ ((__noreturn__)) void rollback(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + security_set_boolean(argv[i], + security_get_boolean_active(argv[i])); + exit(1); +} + +int main(int argc, char **argv) +{ + + int rc, i, commit = 0; + + if (is_selinux_enabled() <= 0) { + fprintf(stderr, "%s: SELinux is disabled\n", argv[0]); + return 1; + } + + if (argc < 2) { + printf("Usage: %s boolname1 [boolname2 ...]\n", + basename(argv[0])); + return 1; + } + + for (i = 1; i < argc; i++) { + printf("%s: ", argv[i]); + rc = security_get_boolean_active(argv[i]); + switch (rc) { + case 1: + if (security_set_boolean(argv[i], 0) >= 0) { + printf("inactive\n"); + commit++; + } else { + printf("%s - rolling back all changes\n", + strerror(errno)); + rollback(i, argv); + } + break; + case 0: + if (security_set_boolean(argv[i], 1) >= 0) { + printf("active\n"); + commit++; + } else { + printf("%s - rolling back all changes\n", + strerror(errno)); + rollback(i, argv); + } + break; + default: + if (errno == ENOENT) + printf + ("Boolean does not exist - rolling back all changes.\n"); + else + printf("%s - rolling back all changes.\n", + strerror(errno)); + rollback(i, argv); + break; /* Not reached. */ + } + } + + if (commit > 0) { + if (security_commit_booleans() < 0) { + printf("Commit failed. (%s) No change to booleans.\n", + strerror(errno)); + } else { + /* syslog all the changes */ + struct passwd *pwd = getpwuid(getuid()); + for (i = 1; i < argc; i++) { + if (pwd && pwd->pw_name) + syslog(LOG_NOTICE, + "The %s policy boolean was toggled by %s", + argv[i], pwd->pw_name); + else + syslog(LOG_NOTICE, + "The %s policy boolean was toggled by uid:%u", + argv[i], getuid()); + + } + return 0; + } + } + return 1; +}