@@ -255,6 +255,19 @@ extern int security_compute_user_raw(const char * scon,
const char *username,
char *** con);
+/* Validate a transition. This determines whether a transition from scon to newcon
+ using tcon as the target for object class tclass is valid in the loaded policy.
+ This checks against the mlsvalidatetrans and validatetrans constraints in the loaded policy.
+ Returns 0 if allowed and -1 if an error occured with errno set */
+extern int security_validatetrans(const char *scon,
+ const char *tcon,
+ security_class_t tclass,
+ const char *newcon);
+extern int security_validatetrans_raw(const char *scon,
+ const char *tcon,
+ security_class_t tclass,
+ const char *newcon);
+
/* Load a policy configuration. */
extern int security_load_policy(void *data, size_t len);
@@ -1,7 +1,7 @@
.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
+security_compute_member, security_compute_user, security_validatetrans, security_get_initial_context \- query
the SELinux policy database in the kernel
.
.SH "SYNOPSIS"
@@ -35,6 +35,10 @@ the SELinux policy database in the kernel
.sp
.BI "int security_compute_user_raw(char *" scon ", const char *" username ", char ***" con );
.sp
+.BI "int security_validatetrans(char *" scon ", const char *" tcon ", security_class_t "tclass ", char *" newcon );
+.sp
+.BI "int security_validatetrans_raw(char *" scon ", const char *" tcon ", security_class_t "tclass ", char *" newcon );
+.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 );
@@ -100,6 +104,12 @@ 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_validatetrans ()
+is used to determine if a transition from scon to newcon using tcon as the object
+is valid for object class tclass. This checks against the mlsvalidatetrans and
+validatetrans constraints in the loaded policy. Returns 0 if allowed, and -1
+if an error occured with errno set.
+
.BR security_get_initial_context ()
is used to get the context of a kernel initial security identifier specified by
.I name
@@ -111,6 +121,7 @@ is used to get the context of a kernel initial security identifier specified by
.BR \%security_compute_relabel_raw (),
.BR \%security_compute_member_raw (),
.BR \%security_compute_user_raw ()
+.BR \%security_validatetrans_raw ()
and
.BR \%security_get_initial_context_raw ()
behave identically to their non-raw counterparts but do not perform context
new file mode 100644
@@ -0,0 +1 @@
+.so man3/security_compute_av.3
new file mode 100644
@@ -0,0 +1 @@
+.so man3/security_compute_av.3
@@ -29,6 +29,8 @@ hidden_proto(selinux_mkload_policy)
hidden_proto(security_compute_create_name_raw)
hidden_proto(security_compute_member_raw)
hidden_proto(security_compute_relabel_raw)
+ hidden_proto(security_validatetrans)
+ hidden_proto(security_validatetrans_raw)
hidden_proto(is_selinux_enabled)
hidden_proto(is_selinux_mls_enabled)
hidden_proto(freecon)
new file mode 100644
@@ -0,0 +1,98 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include "mapping.h"
+
+int security_validatetrans_raw(const char *scon,
+ const char *tcon,
+ security_class_t tclass,
+ const char *newcon)
+{
+ char path[PATH_MAX];
+ char *buf = NULL;
+ int size, bufsz;
+ int fd, ret = -1;
+ errno = ENOENT;
+
+ if (!selinux_mnt) {
+ return -1;
+ }
+
+ snprintf(path, sizeof path, "%s/validatetrans", selinux_mnt);
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ return -1;
+ }
+
+ errno = EINVAL;
+ size = selinux_page_size;
+ buf = malloc(size);
+ if (!buf) {
+ goto out;
+ }
+
+ bufsz = snprintf(NULL, 0, "%s %s %hu %s", scon, tcon, unmap_class(tclass), newcon);
+ if (bufsz > size) {
+ // This is going to be too large
+ goto out;
+ }
+ if (bufsz != snprintf(buf, size, "%s %s %hu %s", scon, tcon, unmap_class(tclass), newcon)) {
+ // It got truncated somehow
+ goto out;
+ }
+
+ // clear errno for write()
+ errno = 0;
+ ret = write(fd, buf, strlen(buf));
+ if (ret > 0) {
+ // The kernel returns the bytes written on success, not 0 as noted in the commit message
+ ret = 0;
+ }
+ free(buf);
+out:
+ close(fd);
+ return ret;
+}
+
+hidden_def(security_validatetrans_raw)
+
+int security_validatetrans(const char *scon,
+ const char *tcon,
+ security_class_t tclass,
+ const char *newcon)
+{
+ int ret = -1;
+ char *rscon = NULL;
+ char *rtcon = NULL;
+ char *rnewcon = NULL;
+
+ if (selinux_trans_to_raw_context(scon, &rscon)) {
+ goto out;
+ }
+
+ if (selinux_trans_to_raw_context(tcon, &rtcon)) {
+ goto out;
+ }
+
+ if (selinux_trans_to_raw_context(newcon, &rnewcon)) {
+ goto out;
+ }
+
+ ret = security_validatetrans_raw(rscon, rtcon, tclass, rnewcon);
+
+out:
+ freecon(rnewcon);
+ freecon(rtcon);
+ freecon(rscon);
+
+ return ret;
+}
+
+hidden_def(security_validatetrans)
@@ -25,3 +25,4 @@ setenforce
setfilecon
togglesebool
selinux_check_access
+validatetrans
new file mode 100644
@@ -0,0 +1,30 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+int main(int argc, char **argv)
+{
+ security_class_t tclass;
+ int ret;
+
+ if (argc != 5) {
+ fprintf(stderr, "usage: %s scontext tcontext tclass newcontext\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_validatetrans(argv[1], argv[2], tclass, argv[4]);
+ printf("security_validatetrans returned %d errno: %s\n", ret, strerror(errno));
+
+ return(ret);
+}
It seems validatetrans support was never added to libselinux, despite being added to selinuxfs in kernel version 4.5 There is a utility to test, however the targeted policy has no validatetrans rules so some must be added: $ cat validatetrans.cil (mlsvalidatetrans db_table (and (or (or (or (eq l1 l2) (and (eq t3 unconfined_t) (domby l1 l2))) (and (eq t3 unconfined_t) (dom l1 l2))) (and (eq t3 unconfined_t) (incomp l1 l2))) (or (or (or (eq l1 h2) (and (eq t3 unconfined_t) (domby h1 h2))) (and (eq t3 unconfined_t) (dom h1 h2))) (and (eq t3 unconfined_t) (incomp h1 h2))))) $ sudo semodule -i validatetrans.cil $ ./validatetrans system_u:system_r:kernel_t:s0 system_u:system_r:init_t:s0:c0 db_table system_u:system_r: # invalid context here opening /sys/fs/selinux/validatetrans security_validatetrans returned -1 errno: Invalid argument $ ./validatetrans system_u:system_r:kernel_t:s0 system_u:system_r:init_t:s0:c0 db_table system_u:system_r:init_t:s0 opening /sys/fs/selinux/validatetrans security_validatetrans returned -1 errno: Operation not permitted $ ./validatetrans system_u:system_r:kernel_t:s0 system_u:system_r:init_t:s0:c0 db_table system_u:system_r:unconfined_t:s0 opening /sys/fs/selinux/validatetrans security_validatetrans returned 0 errno: Success Signed-off-by: Joshua Brindle <joshua.brindle@crunchydata.com> --- libselinux/include/selinux/selinux.h | 13 +++ libselinux/man/man3/security_compute_av.3 | 13 ++- libselinux/man/man3/security_validatetrans.c | 1 + .../man/man3/security_validatetrans_raw.c | 1 + libselinux/src/selinux_internal.h | 2 + libselinux/src/validatetrans.c | 98 +++++++++++++++++++ libselinux/utils/.gitignore | 1 + libselinux/utils/validatetrans.c | 30 ++++++ 8 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 libselinux/man/man3/security_validatetrans.c create mode 100644 libselinux/man/man3/security_validatetrans_raw.c create mode 100644 libselinux/src/validatetrans.c create mode 100644 libselinux/utils/validatetrans.c