aboutsummaryrefslogtreecommitdiff
path: root/lib/libveriexec
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libveriexec')
-rw-r--r--lib/libveriexec/Makefile16
-rw-r--r--lib/libveriexec/Makefile.depend15
-rw-r--r--lib/libveriexec/exec_script.c159
-rw-r--r--lib/libveriexec/gbl_check.c125
-rw-r--r--lib/libveriexec/libveriexec.h55
-rw-r--r--lib/libveriexec/veriexec.363
-rw-r--r--lib/libveriexec/veriexec_check.c145
-rw-r--r--lib/libveriexec/veriexec_get.c341
8 files changed, 919 insertions, 0 deletions
diff --git a/lib/libveriexec/Makefile b/lib/libveriexec/Makefile
new file mode 100644
index 000000000000..9cef42a7cf58
--- /dev/null
+++ b/lib/libveriexec/Makefile
@@ -0,0 +1,16 @@
+.include <src.opts.mk>
+
+LIB= veriexec
+MAN= veriexec.3
+INCS= libveriexec.h
+
+WARNS?= 2
+
+SRCS= \
+ exec_script.c \
+ gbl_check.c \
+ veriexec_check.c \
+ veriexec_get.c \
+
+.include <bsd.lib.mk>
+
diff --git a/lib/libveriexec/Makefile.depend b/lib/libveriexec/Makefile.depend
new file mode 100644
index 000000000000..6ef78fac5cbf
--- /dev/null
+++ b/lib/libveriexec/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libveriexec/exec_script.c b/lib/libveriexec/exec_script.c
new file mode 100644
index 000000000000..cdbbbab54a03
--- /dev/null
+++ b/lib/libveriexec/exec_script.c
@@ -0,0 +1,159 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2023, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/mac.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <security/mac_grantbylabel/mac_grantbylabel.h>
+
+#include "libveriexec.h"
+
+static char *
+find_interpreter(const char *script)
+{
+ static const char ws[] = " \t\n\r";
+ static char buf[MAXPATHLEN+4]; /* allow space for #! etc */
+ char *cp;
+ int fd;
+ int n;
+
+ cp = NULL;
+ if ((fd = open(script, O_RDONLY)) >= 0) {
+ if ((n = read(fd, buf, sizeof(buf))) > 0) {
+ if (strncmp(buf, "#!", 2) == 0) {
+ buf[sizeof(buf) - 1] = '\0';
+ cp = &buf[2];
+ if ((n = strspn(cp, ws)) > 0)
+ cp += n;
+ if ((n = strcspn(cp, ws)) > 0) {
+ cp[n] = '\0';
+ } else {
+ cp = NULL;
+ }
+ }
+ }
+ close(fd);
+ }
+ return (cp);
+}
+
+/**
+ * @brief exec a python or similar script
+ *
+ * Python and similar scripts must normally be signed and
+ * run directly rather than fed to the interpreter which
+ * is not normally allowed to be run directly.
+ *
+ * If direct execv of script fails due to EAUTH
+ * and process has GBL_VERIEXEC syslog event and run via
+ * interpreter.
+ *
+ * If interpreter is NULL look at first block of script
+ * to find ``#!`` magic.
+ *
+ * @prarm[in] interpreter
+ * if NULL, extract from script if necessary
+ *
+ * @prarm[in] argv
+ * argv for execv(2)
+ * argv[0] must be full path.
+ * Python at least requires argv[1] to also be the script path.
+ *
+ * @return
+ * error on failure usually EPERM or EAUTH
+ */
+int
+execv_script(const char *interpreter, char * const *argv)
+{
+ const char *script;
+ int rc;
+
+ script = argv[0];
+ if (veriexec_check_path(script) == 0) {
+ rc = execv(script, argv);
+ }
+ /* still here? we might be allowed to run via interpreter */
+ if (gbl_check_pid(0) & GBL_VERIEXEC) {
+ if (!interpreter)
+ interpreter = find_interpreter(script);
+ if (interpreter) {
+ syslog(LOG_NOTICE, "running %s via %s",
+ script, interpreter);
+ rc = execv(interpreter, argv);
+ }
+ }
+ return (rc);
+}
+
+#if defined(MAIN) || defined(UNIT_TEST)
+#include <sys/wait.h>
+#include <err.h>
+
+int
+main(int argc __unused, char *argv[])
+{
+ const char *interp;
+ int c;
+ int s;
+ pid_t child;
+
+ openlog("exec_script", LOG_PID|LOG_PERROR, LOG_DAEMON);
+
+ interp = NULL;
+ while ((c = getopt(argc, argv, "i:")) != -1) {
+ switch (c) {
+ case 'i':
+ interp = optarg;
+ break;
+ default:
+ errx(1, "unknown option: -%c", c);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ /* we need a child */
+ child = fork();
+ if (child < 0)
+ err(2, "fork");
+ if (child == 0) {
+ c = execv_script(interp, argv);
+ err(2, "exec_script(%s,%s)", interp, argv[0]);
+ }
+ c = waitpid(child, &s, 0);
+ printf("%s: exit %d\n", argv[0], WEXITSTATUS(s));
+ return (0);
+}
+#endif
diff --git a/lib/libveriexec/gbl_check.c b/lib/libveriexec/gbl_check.c
new file mode 100644
index 000000000000..c0da93d0857c
--- /dev/null
+++ b/lib/libveriexec/gbl_check.c
@@ -0,0 +1,125 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2023, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mac.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <security/mac_grantbylabel/mac_grantbylabel.h>
+
+/**
+ * @brief does path have a gbl label
+ *
+ * @return
+ * @li 0 if no/empty label or module not loaded
+ * @li value of label
+ */
+unsigned int
+gbl_check_path(const char *path)
+{
+ struct mac_grantbylabel_fetch_gbl_args gbl;
+ int fd;
+ int rc;
+
+ rc = 0;
+ if ((fd = open(path, O_RDONLY|O_VERIFY)) >= 0) {
+ gbl.u.fd = fd;
+ if (mac_syscall(MAC_GRANTBYLABEL_NAME,
+ MAC_GRANTBYLABEL_FETCH_GBL,
+ &gbl) == 0) {
+ if (gbl.gbl != GBL_EMPTY)
+ rc = gbl.gbl;
+ }
+ close(fd);
+ }
+ return(rc);
+}
+
+/**
+ * @brief does pid have a gbl label
+ *
+ * @return
+ * @li 0 if no/empty label or module not loaded
+ * @li value of label
+ */
+unsigned int
+gbl_check_pid(pid_t pid)
+{
+ struct mac_grantbylabel_fetch_gbl_args gbl;
+ int rc;
+
+ rc = 0;
+ gbl.u.pid = pid;
+ if (mac_syscall(MAC_GRANTBYLABEL_NAME,
+ MAC_GRANTBYLABEL_FETCH_PID_GBL, &gbl) == 0) {
+ if (gbl.gbl != GBL_EMPTY)
+ rc = gbl.gbl;
+ }
+ return(rc);
+}
+
+
+#ifdef UNIT_TEST
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+
+int
+main(int argc, char *argv[])
+{
+ pid_t pid;
+ int pflag = 0;
+ int c;
+ unsigned int gbl;
+
+ while ((c = getopt(argc, argv, "p")) != -1) {
+ switch (c) {
+ case 'p':
+ pflag = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ for (; optind < argc; optind++) {
+
+ if (pflag) {
+ pid = atoi(argv[optind]);
+ gbl = gbl_check_pid(pid);
+ } else {
+ gbl = gbl_check_path(argv[optind]);
+ }
+ printf("arg=%s, gbl=%#o\n", argv[optind], gbl);
+ }
+ return 0;
+}
+#endif
diff --git a/lib/libveriexec/libveriexec.h b/lib/libveriexec/libveriexec.h
new file mode 100644
index 000000000000..32b2f20d6123
--- /dev/null
+++ b/lib/libveriexec/libveriexec.h
@@ -0,0 +1,55 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011-2023, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __LIBVERIEXEC_H__
+#define __LIBVERIEXEC_H__
+
+struct mac_veriexec_syscall_params;
+
+int veriexec_check_fd_mode(int, unsigned int);
+int veriexec_check_path_mode(const char *, unsigned int);
+int veriexec_check_fd(int);
+int veriexec_check_path(const char *);
+int veriexec_get_pid_params(pid_t, struct mac_veriexec_syscall_params *);
+int veriexec_get_path_params(const char *,
+ struct mac_veriexec_syscall_params *);
+int veriexec_check_path_label(const char *, const char *);
+int veriexec_check_pid_label(pid_t, const char *);
+char * veriexec_get_path_label(const char *, char *, size_t);
+char * veriexec_get_pid_label(pid_t, char *, size_t);
+unsigned int gbl_check_path(const char *);
+unsigned int gbl_check_pid(pid_t);
+int execv_script(const char *, char * const *);
+
+#define HAVE_GBL_CHECK_PID 1
+#define HAVE_VERIEXEC_CHECK_PATH_LABEL 1
+#define HAVE_VERIEXEC_CHECK_PID_LABEL 1
+#define HAVE_VERIEXEC_GET_PATH_LABEL 1
+#define HAVE_VERIEXEC_GET_PID_LABEL 1
+
+#endif /* __LIBVERIEXEC_H__ */
diff --git a/lib/libveriexec/veriexec.3 b/lib/libveriexec/veriexec.3
new file mode 100644
index 000000000000..b367fc5ea40f
--- /dev/null
+++ b/lib/libveriexec/veriexec.3
@@ -0,0 +1,63 @@
+.\" Copyright (c) 2018, Juniper Networks, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd June 19, 2018
+.Dt VERIEXEC 3
+.Os
+.Sh NAME
+.Nm veriexec_check_fd ,
+.Nm veriexec_check_path
+.Nd Verified execution routines
+.Sh LIBRARY
+.Lb libveriexec
+.Sh SYNOPSIS
+.In libveriexec.h
+.Ft int
+.Fn veriexec_check_fd "int fd"
+.Ft int
+.Fn veriexec_check_path "const char *file"
+.Sh DESCRIPTION
+The
+.Fn veriexec_check_fd
+function checks the signature of the file represented by the
+.Fa fd
+file descriptor.
+.Pp
+The
+.Fn veriexec_check_path
+function checks the signature of the file path
+.Fa file .
+.Pp
+The
+.Fn veriexec_check_fd
+and
+.Fn veriexec_check_path
+functions return zero on a successful signature match or if veriexec is not
+enabled.
+If the signature does not match,
+.Va errno
+is set to the reason for the mismatch.
+.Sh SEE ALSO
+.Xr mac_veriexec 4 ,
+.Xr veriexec 4
diff --git a/lib/libveriexec/veriexec_check.c b/lib/libveriexec/veriexec_check.c
new file mode 100644
index 000000000000..311eb307f25d
--- /dev/null
+++ b/lib/libveriexec/veriexec_check.c
@@ -0,0 +1,145 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011, 2012, 2013, 2015, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mac.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+#include "libveriexec.h"
+
+
+static int
+check_fd_mode(int fd, unsigned int mask)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return errno;
+
+ if ((st.st_mode & mask) == 0)
+ return EAUTH;
+
+ return 0;
+}
+
+int
+veriexec_check_fd_mode(int fd, unsigned int mask)
+{
+ int error;
+
+ if (fd < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ error = mac_syscall(MAC_VERIEXEC_NAME, MAC_VERIEXEC_CHECK_FD_SYSCALL,
+ (void *)(intptr_t)fd);
+ if (error == -1) {
+ switch (errno) {
+ case ENOSYS: /* veriexec not loaded */
+ error = 0; /* ignore */
+ break;
+ }
+ }
+ if (mask && error == 0)
+ error = check_fd_mode(fd, mask);
+
+ return (error);
+}
+
+int
+veriexec_check_path_mode(const char *file, unsigned int mask)
+{
+ int error;
+
+ if (!file) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (mask) {
+ int fd;
+
+ if ((fd = open(file, O_RDONLY)) < 0)
+ return errno;
+
+ error = veriexec_check_fd_mode(fd, mask);
+ close(fd);
+ return error;
+ }
+
+ error = mac_syscall(MAC_VERIEXEC_NAME, MAC_VERIEXEC_CHECK_PATH_SYSCALL,
+ __DECONST(void *, file));
+ if (error == -1) {
+ switch (errno) {
+ case ENOSYS: /* veriexec not loaded */
+ error = 0; /* ignore */
+ break;
+ }
+ }
+ return (error);
+}
+
+int
+veriexec_check_fd(int fd)
+{
+ return veriexec_check_fd_mode(fd, 0);
+}
+
+int
+veriexec_check_path(const char *file)
+{
+ return veriexec_check_path_mode(file, 0);
+}
+
+#if defined(MAIN) || defined(UNIT_TEST)
+int
+main(int argc __unused, char *argv[] __unused)
+{
+ int error;
+ int rc = 0;
+
+ while (*++argv) {
+ error = veriexec_check_path(*argv);
+ if (error == -1) {
+ rc = 1;
+ warn("%s", *argv);
+ }
+ }
+ exit(rc);
+}
+#endif
diff --git a/lib/libveriexec/veriexec_get.c b/lib/libveriexec/veriexec_get.c
new file mode 100644
index 000000000000..0707e184a983
--- /dev/null
+++ b/lib/libveriexec/veriexec_get.c
@@ -0,0 +1,341 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2023, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mac.h>
+
+#include <unistd.h>
+#include <string.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+/**
+ * @brief get veriexec params for a process
+ *
+ * @return
+ * @li 0 if successful
+ */
+int
+veriexec_get_pid_params(pid_t pid,
+ struct mac_veriexec_syscall_params *params)
+{
+ struct mac_veriexec_syscall_params_args args;
+
+ if (params == NULL)
+ return EINVAL;
+
+ args.u.pid = pid;
+ args.params = params;
+ return mac_syscall(MAC_VERIEXEC_NAME,
+ MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL, &args);
+}
+
+/**
+ * @brief get veriexec params for a path
+ *
+ * @return
+ * @li 0 if successful
+ */
+int
+veriexec_get_path_params(const char *file,
+ struct mac_veriexec_syscall_params *params)
+{
+ struct mac_veriexec_syscall_params_args args;
+
+ if (file == NULL || params == NULL)
+ return EINVAL;
+
+ args.u.filename = file;
+ args.params = params;
+ return mac_syscall(MAC_VERIEXEC_NAME,
+ MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL, &args);
+}
+
+/**
+ * @brief return label associated with a path
+ *
+ * @param[in] file
+ * pathname of file to lookup.
+ *
+ * @prarm[in] buf
+ * if not NULL and big enough copy label to buf.
+ * otherwise return a copy of label.
+ *
+ * @param[in] bufsz
+ * size of buf, must be greater than found label length.
+ *
+ * @return
+ * @li NULL if no label
+ * @li pointer to label
+ */
+char *
+veriexec_get_path_label(const char *file, char *buf, size_t bufsz)
+{
+ struct mac_veriexec_syscall_params params;
+ char *cp;
+
+ cp = NULL;
+ if (veriexec_get_path_params(file, &params) == 0) {
+ /* Does label contain a label */
+ if (params.labellen > 0) {
+ if (buf != NULL && bufsz > params.labellen) {
+ strlcpy(buf, params.label, bufsz);
+ cp = buf;
+ } else
+ cp = strdup(params.label);
+ }
+ }
+ return cp;
+}
+
+/**
+ * @brief return label of a process
+ *
+ *
+ * @param[in] pid
+ * process id of interest.
+ *
+ * @prarm[in] buf
+ * if not NULL and big enough copy label to buf.
+ * otherwise return a copy of label.
+ *
+ * @param[in] bufsz
+ * size of buf, must be greater than found label length.
+ *
+ * @return
+ * @li NULL if no label
+ * @li pointer to label
+ */
+char *
+veriexec_get_pid_label(pid_t pid, char *buf, size_t bufsz)
+{
+ struct mac_veriexec_syscall_params params;
+ char *cp;
+
+ cp = NULL;
+ if (veriexec_get_pid_params(pid, &params) == 0) {
+ /* Does label contain a label */
+ if (params.labellen > 0) {
+ if (buf != NULL && bufsz > params.labellen) {
+ strlcpy(buf, params.label, bufsz);
+ cp = buf;
+ } else
+ cp = strdup(params.label);
+ }
+ }
+ return cp;
+}
+
+/*
+ * we match
+ * ^want$
+ * ^want,
+ * ,want,
+ * ,want$
+ *
+ * and if want ends with / then we match that prefix too.
+ */
+static int
+check_label_want(const char *label, size_t labellen,
+ const char *want, size_t wantlen)
+{
+ char *cp;
+
+ /* Does label contain [,]<want>[,] ? */
+ if (labellen > 0 && wantlen > 0 &&
+ (cp = strstr(label, want)) != NULL) {
+ if (cp == label || cp[-1] == ',') {
+ if (cp[wantlen] == '\0' || cp[wantlen] == ',' ||
+ (cp[wantlen-1] == '/' && want[wantlen-1] == '/'))
+ return 1; /* yes */
+ }
+ }
+ return 0; /* no */
+}
+
+/**
+ * @brief check if a process has label that contains what we want
+ *
+ * @param[in] pid
+ * process id of interest.
+ *
+ * @param[in] want
+ * the label we are looking for
+ * if want ends with ``/`` it is assumed a prefix
+ * otherwise we expect it to be followed by ``,`` or end of string.
+ *
+ * @return
+ * @li 0 if no
+ * @li 1 if yes
+ */
+int
+veriexec_check_pid_label(pid_t pid, const char *want)
+{
+ struct mac_veriexec_syscall_params params;
+ size_t n;
+
+ if (want != NULL &&
+ (n = strlen(want)) > 0 &&
+ veriexec_get_pid_params(pid, &params) == 0) {
+ return check_label_want(params.label, params.labellen,
+ want, n);
+ }
+ return 0; /* no */
+}
+
+/**
+ * @brief check if a path has label that contains what we want
+ *
+ * @param[in] path
+ * pathname of interest.
+ *
+ * @param[in] want
+ * the label we are looking for
+ * if want ends with ``/`` it is assumed a prefix
+ * otherwise we expect it to be followed by ``,`` or end of string.
+ *
+ * @return
+ * @li 0 if no
+ * @li 1 if yes
+ */
+int
+veriexec_check_path_label(const char *file, const char *want)
+{
+ struct mac_veriexec_syscall_params params;
+ size_t n;
+
+ if (want != NULL && file != NULL &&
+ (n = strlen(want)) > 0 &&
+ veriexec_get_path_params(file, &params) == 0) {
+ return check_label_want(params.label, params.labellen,
+ want, n);
+ }
+ return 0; /* no */
+}
+
+#ifdef UNIT_TEST
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+
+static char *
+hash2hex(char *type, unsigned char *digest)
+{
+ static char buf[2*MAXFINGERPRINTLEN+1];
+ size_t n;
+ int i;
+
+ if (strcmp(type, "SHA1") == 0) {
+ n = 20;
+ } else if (strcmp(type, "SHA256") == 0) {
+ n = 32;
+ } else if (strcmp(type, "SHA384") == 0) {
+ n = 48;
+ }
+ for (i = 0; i < n; i++) {
+ sprintf(&buf[2*i], "%02x", (unsigned)digest[i]);
+ }
+ return buf;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct mac_veriexec_syscall_params params;
+ pid_t pid;
+ char buf[BUFSIZ];
+ const char *cp;
+ char *want = NULL;
+ int lflag = 0;
+ int pflag = 0;
+ int error;
+ int c;
+
+ while ((c = getopt(argc, argv, "lpw:")) != -1) {
+ switch (c) {
+ case 'l':
+ lflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'w':
+ want = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+ for (; optind < argc; optind++) {
+
+ if (pflag) {
+ pid = atoi(argv[optind]);
+ if (lflag) {
+ cp = veriexec_get_pid_label(pid, buf, sizeof(buf));
+ if (cp)
+ printf("pid=%d label='%s'\n", pid, cp);
+ continue;
+ }
+ if (want) {
+ error = veriexec_check_pid_label(pid, want);
+ printf("pid=%d want='%s': %d\n",
+ pid, want, error);
+ continue;
+ }
+ error = veriexec_get_pid_params(pid, &params);
+ } else {
+ if (lflag) {
+ cp = veriexec_get_path_label(argv[optind],
+ buf, sizeof(buf));
+ if (cp)
+ printf("path='%s' label='%s'\n",
+ argv[optind], cp);
+ continue;
+ }
+ if (want) {
+ error = veriexec_check_path_label(argv[optind], want);
+ printf("path='%s' want='%s': %d\n",
+ argv[optind], want, error);
+ continue;
+ }
+ error = veriexec_get_path_params(argv[optind], &params);
+ }
+ if (error) {
+ err(2, "%s, error=%d", argv[optind], error);
+ }
+
+ printf("arg=%s, type=%s, flags=%u, label='%s', fingerprint='%s'\n",
+ argv[optind], params.fp_type, (unsigned)params.flags,
+ params.label,
+ hash2hex(params.fp_type, params.fingerprint));
+ }
+ return 0;
+}
+#endif