diff options
Diffstat (limited to 'lib/libveriexec')
-rw-r--r-- | lib/libveriexec/Makefile | 16 | ||||
-rw-r--r-- | lib/libveriexec/Makefile.depend | 15 | ||||
-rw-r--r-- | lib/libveriexec/exec_script.c | 159 | ||||
-rw-r--r-- | lib/libveriexec/gbl_check.c | 125 | ||||
-rw-r--r-- | lib/libveriexec/libveriexec.h | 55 | ||||
-rw-r--r-- | lib/libveriexec/veriexec.3 | 63 | ||||
-rw-r--r-- | lib/libveriexec/veriexec_check.c | 145 | ||||
-rw-r--r-- | lib/libveriexec/veriexec_get.c | 341 |
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, ¶ms) == 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, ¶ms) == 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, ¶ms) == 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, ¶ms) == 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, ¶ms); + } 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], ¶ms); + } + 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 |