Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131854454
D41431.id125892.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D41431.id125892.diff
View Options
diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist
--- a/etc/mtree/BSD.include.dist
+++ b/etc/mtree/BSD.include.dist
@@ -334,6 +334,8 @@
..
mac_bsdextended
..
+ mac_grantbylabel
+ ..
mac_lomac
..
mac_mls
diff --git a/include/Makefile b/include/Makefile
--- a/include/Makefile
+++ b/include/Makefile
@@ -68,7 +68,9 @@
netinet/netdump \
netinet/tcp_stacks \
netlink/route \
- security/mac_biba security/mac_bsdextended security/mac_lomac \
+ security/mac_biba security/mac_bsdextended \
+ security/mac_grantbylabel \
+ security/mac_lomac \
security/mac_mls security/mac_partition \
security/mac_veriexec \
sys/disk \
diff --git a/lib/libveriexec/Makefile b/lib/libveriexec/Makefile
--- a/lib/libveriexec/Makefile
+++ b/lib/libveriexec/Makefile
@@ -9,8 +9,10 @@
WARNS?= 2
SRCS= \
+ exec_script.c \
+ gbl_check.c \
veriexec_check.c \
- veriexec_get.c
+ veriexec_get.c \
.include <bsd.lib.mk>
diff --git a/lib/libveriexec/exec_script.c b/lib/libveriexec/exec_script.c
new file mode 100644
--- /dev/null
+++ b/lib/libveriexec/exec_script.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019, 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.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+#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
--- /dev/null
+++ b/lib/libveriexec/gbl_check.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2019, 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.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+#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
--- a/lib/libveriexec/libveriexec.h
+++ b/lib/libveriexec/libveriexec.h
@@ -40,7 +40,11 @@
struct mac_veriexec_syscall_params *);
int veriexec_check_path_label(const char *, const char *);
int veriexec_check_pid_label(pid_t, const char *);
+unsigned int gbl_check_path(const char *);
+unsigned int gbl_check_pid(pid_t);
+int execv_script(const char *, char * const *);
-#define HAVE_VERIEXEC_CHECK_PID_LABEL 1
+#define HAVE_GBL_CHECK_PID 1
+#define HAVE_VERIEXEC_CHECK_PID_LABEL 1
#endif /* __LIBVERIEXEC_H__ */
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -5143,6 +5143,7 @@
security/mac_seeotheruids/mac_seeotheruids.c optional mac_seeotheruids
security/mac_stub/mac_stub.c optional mac_stub
security/mac_test/mac_test.c optional mac_test
+security/mac_grantbylabel/mac_grantbylabel.c optional mac_grantbylabel
security/mac_veriexec/mac_veriexec.c optional mac_veriexec
security/mac_veriexec/veriexec_fingerprint.c optional mac_veriexec
security/mac_veriexec/veriexec_metadata.c optional mac_veriexec
diff --git a/sys/conf/options b/sys/conf/options
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -169,6 +169,7 @@
MAC_STATIC opt_mac.h
MAC_STUB opt_dontuse.h
MAC_TEST opt_dontuse.h
+MAC_GRANTBYLABEL opt_dontuse.h
MAC_VERIEXEC opt_dontuse.h
MAC_VERIEXEC_SHA1 opt_dontuse.h
MAC_VERIEXEC_SHA256 opt_dontuse.h
diff --git a/lib/libveriexec/libveriexec.h b/sys/security/mac_grantbylabel/mac_grantbylabel.h
copy from lib/libveriexec/libveriexec.h
copy to sys/security/mac_grantbylabel/mac_grantbylabel.h
--- a/lib/libveriexec/libveriexec.h
+++ b/sys/security/mac_grantbylabel/mac_grantbylabel.h
@@ -1,7 +1,7 @@
-/*-
+/*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2011, 2012, 2013, 2015, Juniper Networks, Inc.
+ * Copyright (c) 2018-2023, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,21 +26,38 @@
* SUCH DAMAGE.
*/
-#ifndef __LIBVERIEXEC_H__
-#define __LIBVERIEXEC_H__
+#ifndef _SECURITY_MAC_GRANTBYLABEL_H
+#define _SECURITY_MAC_GRANTBYLABEL_H
-struct mac_veriexec_syscall_params;
+#include <security/mac_veriexec/mac_veriexec.h>
-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 *);
+#define MAC_GRANTBYLABEL_NAME "mac_grantbylabel"
-#define HAVE_VERIEXEC_CHECK_PID_LABEL 1
+/* the bits we use to represent tokens */
+#define GBL_EMPTY (1<<0)
+#define GBL_BIND (1<<1)
+#define GBL_IPC (1<<2)
+#define GBL_NET (1<<3)
+#define GBL_PROC (1<<4)
+#define GBL_RTSOCK (1<<5)
+#define GBL_SYSCTL (1<<6)
+#define GBL_VACCESS (1<<7)
+#define GBL_VERIEXEC (1<<8)
+#define GBL_KMEM (1<<9)
+#define GBL_MAX 9
-#endif /* __LIBVERIEXEC_H__ */
+/* this should suffice for now */
+typedef uint32_t gbl_label_t;
+
+#define MAC_GRANTBYLABEL_FETCH_GBL 1
+#define MAC_GRANTBYLABEL_FETCH_PID_GBL 2
+
+struct mac_grantbylabel_fetch_gbl_args {
+ union {
+ int fd;
+ pid_t pid;
+ } u;
+ gbl_label_t gbl;
+};
+
+#endif
diff --git a/sys/security/mac_grantbylabel/mac_grantbylabel.c b/sys/security/mac_grantbylabel/mac_grantbylabel.c
new file mode 100644
--- /dev/null
+++ b/sys/security/mac_grantbylabel/mac_grantbylabel.c
@@ -0,0 +1,509 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2018-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/cdefs.h>
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mac.h>
+#include <sys/namei.h>
+#include <sys/priv.h>
+#include <sys/imgact.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <security/mac/mac_policy.h>
+
+#include "mac_grantbylabel.h"
+#include <security/mac_veriexec/mac_veriexec_internal.h>
+
+#define MAC_GRANTBYLABEL_FULLNAME "MAC/grantbylabel"
+
+#define GRANTBYLABEL_DEBUG(n, x) if (mac_grantbylabel_debug >= (n)) printf x
+
+static int mac_grantbylabel_debug;
+
+SYSCTL_DECL(_security_mac);
+SYSCTL_NODE(_security_mac, OID_AUTO, grantbylabel, CTLFLAG_RW, 0,
+ "MAC/grantbylabel policy controls");
+SYSCTL_INT(_security_mac_grantbylabel, OID_AUTO, debug, CTLFLAG_RW,
+ &mac_grantbylabel_debug, 0, "Debug mac_grantbylabel");
+
+#ifdef MAC_DEBUG
+#define MAC_GRANTBYLABEL_DBG(_lvl, _fmt, ...) \
+ do { \
+ GRANTBYLABEL_DEBUG((_lvl), (MAC_GRANTBYLABEL_FULLNAME ": " _fmt \
+ "\n", ##__VA_ARGS__)); \
+ } while(0)
+#else
+#define MAC_GRANTBYLABEL_DBG(_lvl, _fmt, ...)
+#endif
+
+
+/* label token prefix */
+#define GBL_PREFIX "gbl/"
+
+static int mac_grantbylabel_slot;
+
+#define SLOT(l) \
+ mac_label_get((l), mac_grantbylabel_slot)
+#define SLOT_SET(l, v) \
+ mac_label_set((l), mac_grantbylabel_slot, (v))
+
+
+/**
+ * @brief parse label into bitmask
+ *
+ * We are only interested in tokens prefixed by GBL_PREFIX ("gbl/").
+ *
+ * @return 32bit mask
+ */
+static gbl_label_t
+gbl_parse_label(const char *label)
+{
+ gbl_label_t gbl;
+ char *cp;
+
+ if (!(label && *label))
+ return GBL_EMPTY;
+ gbl = 0;
+ for (cp = strstr(label, GBL_PREFIX); cp; cp = strstr(cp, GBL_PREFIX)) {
+ /* check we didn't find "fugbl/" */
+ if (cp > label && cp[-1] != ',') {
+ cp += sizeof(GBL_PREFIX);
+ continue;
+ }
+ cp += sizeof(GBL_PREFIX) - 1;
+ switch (*cp) {
+ case 'b':
+ if (strncmp(cp, "bind", 4) == 0)
+ gbl |= GBL_BIND;
+ break;
+ case 'd':
+ if (strncmp(cp, "daemon", 6) == 0)
+ gbl |= (GBL_BIND|GBL_IPC|GBL_NET|GBL_PROC|
+ GBL_SYSCTL|GBL_VACCESS);
+ break;
+ case 'i':
+ if (strncmp(cp, "ipc", 3) == 0)
+ gbl |= GBL_IPC;
+ break;
+ case 'k':
+ if (strncmp(cp, "kmem", 4) == 0)
+ gbl |= GBL_KMEM;
+ break;
+ case 'n':
+ if (strncmp(cp, "net", 3) == 0)
+ gbl |= GBL_NET;
+ break;
+ case 'p':
+ if (strncmp(cp, "proc", 4) == 0)
+ gbl |= GBL_PROC;
+ break;
+ case 'r':
+ if (strncmp(cp, "rtsock", 6) == 0)
+ gbl |= GBL_RTSOCK;
+ break;
+ case 's':
+ if (strncmp(cp, "sysctl", 6) == 0)
+ gbl |= GBL_SYSCTL;
+ break;
+ case 'v':
+ if (strncmp(cp, "vaccess", 7) == 0)
+ gbl |= GBL_VACCESS;
+ else if (strncmp(cp, "veriexec", 8) == 0)
+ gbl |= GBL_VERIEXEC;
+ break;
+ default: /* ignore unknown? */
+ MAC_GRANTBYLABEL_DBG(1,
+ "ignoring unknown token at %s/%s",
+ GBL_PREFIX, cp);
+ break;
+ }
+ }
+
+ return gbl;
+}
+
+
+/**
+ * @brief get the v_label for a vnode
+ *
+ * Lookup the label if not already set in v_label
+ *
+ * @return 32bit mask or 0 on error
+ */
+static gbl_label_t
+gbl_get_vlabel(struct vnode *vp, struct ucred *cred)
+{
+ struct vattr va;
+ const char *label;
+ gbl_label_t gbl;
+ int error;
+
+ gbl = SLOT(vp->v_label);
+ if (gbl == 0) {
+ error = VOP_GETATTR(vp, &va, cred);
+ if (error == 0) {
+ label = mac_veriexec_metadata_get_file_label(va.va_fsid,
+ va.va_fileid, va.va_gen, FALSE);
+ if (label) {
+ MAC_GRANTBYLABEL_DBG(1,
+ "label=%s dev=%ju, file %ju.%lu",
+ label,
+ (uintmax_t)va.va_fsid,
+ (uintmax_t)va.va_fileid,
+ va.va_gen);
+ gbl = gbl_parse_label(label);
+ } else {
+ gbl = GBL_EMPTY;
+ MAC_GRANTBYLABEL_DBG(2, "no label dev=%ju, file %ju.%lu",
+ (uintmax_t)va.va_fsid,
+ (uintmax_t)va.va_fileid,
+ va.va_gen);
+ }
+ }
+ }
+ return gbl;
+}
+
+
+/**
+ * @brief grant priv if warranted
+ *
+ * If the cred is root, we have nothing to do.
+ * Otherwise see if the current process has a label
+ * that grants it the requested priv.
+ */
+static int
+mac_grantbylabel_priv_grant(struct ucred *cred, int priv)
+{
+ gbl_label_t label;
+ int rc;
+
+ rc = EPERM; /* default response */
+
+ if ((curproc->p_flag & (P_KPROC|P_SYSTEM)))
+ return rc; /* not interested */
+
+ switch (priv) {
+ case PRIV_KMEM_READ:
+ case PRIV_KMEM_WRITE:
+ break;
+ case PRIV_VERIEXEC_DIRECT:
+ case PRIV_VERIEXEC_NOVERIFY:
+ /* XXX might want to skip in FIPS mode */
+ break;
+ default:
+ if (cred->cr_uid == 0)
+ return rc; /* not interested */
+ break;
+ }
+
+ label = (gbl_label_t)(SLOT(curproc->p_textvp->v_label) |
+ SLOT(curproc->p_label));
+
+ /*
+ * We look at the extra privs granted
+ * via process label.
+ */
+ switch (priv) {
+ case PRIV_IPC_READ:
+ case PRIV_IPC_WRITE:
+ if (label & GBL_IPC)
+ rc = 0;
+ break;
+ case PRIV_KMEM_READ:
+ case PRIV_KMEM_WRITE:
+ if (label & GBL_KMEM)
+ rc = 0;
+ break;
+ case PRIV_NETINET_BINDANY:
+ case PRIV_NETINET_RESERVEDPORT: /* socket bind low port */
+ case PRIV_NETINET_REUSEPORT:
+ if (label & GBL_BIND)
+ rc = 0;
+ break;
+ case PRIV_NETINET_ADDRCTRL6:
+ case PRIV_NET_LAGG:
+ case PRIV_NET_SETIFFIB:
+ case PRIV_NET_SETIFVNET:
+ case PRIV_NETINET_SETHDROPTS:
+ case PRIV_NET_VXLAN:
+ case PRIV_NETINET_GETCRED:
+ case PRIV_NETINET_IPSEC:
+ case PRIV_NETINET_RAW:
+ if (label & GBL_NET)
+ rc = 0;
+ break;
+ case PRIV_NETINET_MROUTE:
+ case PRIV_NET_ROUTE:
+ if (label & GBL_RTSOCK)
+ rc = 0;
+ break;
+ case PRIV_PROC_LIMIT:
+ case PRIV_PROC_SETRLIMIT:
+ if (label & GBL_PROC)
+ rc = 0;
+ break;
+ case PRIV_SYSCTL_WRITE:
+ if (label & GBL_SYSCTL)
+ rc = 0;
+ break;
+ case PRIV_VFS_READ:
+ case PRIV_VFS_WRITE:
+ if (label & GBL_KMEM)
+ rc = 0;
+ /* FALLTHROUGH */
+ case PRIV_VFS_ADMIN:
+ case PRIV_VFS_BLOCKRESERVE:
+ case PRIV_VFS_CHOWN:
+ case PRIV_VFS_EXEC: /* vaccess file and accmode & VEXEC */
+ case PRIV_VFS_GENERATION:
+ case PRIV_VFS_LOOKUP: /* vaccess DIR */
+ if (label & GBL_VACCESS)
+ rc = 0;
+ break;
+ case PRIV_VERIEXEC_DIRECT:
+ /*
+ * We are here because we are attempting to direct exec
+ * something with the 'indirect' flag set.
+ * We need to check parent label for this one.
+ */
+ PROC_LOCK(curproc);
+ label = (gbl_label_t)SLOT(curproc->p_pptr->p_textvp->v_label);
+ if (label & GBL_VERIEXEC) {
+ rc = 0;
+ /*
+ * Of course the only reason to be running an
+ * interpreter this way is to bypass O_VERIFY
+ * so we can run unsigned script.
+ * We set GBL_VERIEXEC on p_label for
+ * PRIV_VERIEXEC_NOVERIFY below
+ */
+ SLOT_SET(curproc->p_label, GBL_VERIEXEC);
+ }
+ PROC_UNLOCK(curproc);
+ break;
+ case PRIV_VERIEXEC_NOVERIFY:
+ /* we look at p_label! see above */
+ label = (gbl_label_t)SLOT(curproc->p_label);
+ if (label & GBL_VERIEXEC)
+ rc = 0;
+ break;
+ default:
+ break;
+ }
+ MAC_GRANTBYLABEL_DBG(rc ? 1 : 2,
+ "pid=%d priv=%d, label=%#o rc=%d",
+ curproc->p_pid, priv, label, rc);
+
+ return rc;
+}
+
+
+/*
+ * If proc->p_textvp does not yet have a label,
+ * fetch file info from mac_veriexec
+ * and set label (if any) else set.
+ * If there is no label set it to GBL_EMPTY.
+ */
+static int
+mac_grantbylabel_proc_check_resource(struct ucred *cred,
+ struct proc *proc)
+{
+ gbl_label_t gbl;
+
+ if (!SLOT(proc->p_textvp->v_label)) {
+ gbl = gbl_get_vlabel(proc->p_textvp, cred);
+ if (gbl == 0)
+ gbl = GBL_EMPTY;
+ SLOT_SET(proc->p_textvp->v_label, gbl);
+ }
+ return 0;
+}
+
+static int
+mac_grantbylabel_syscall(struct thread *td, int call, void *arg)
+{
+ cap_rights_t rights;
+ struct mac_grantbylabel_fetch_gbl_args gbl_args;
+ struct file *fp;
+ struct proc *proc;
+ int error;
+ int proc_locked;
+
+ switch (call) {
+ case MAC_GRANTBYLABEL_FETCH_GBL:
+ case MAC_GRANTBYLABEL_FETCH_PID_GBL:
+ error = copyin(arg, &gbl_args, sizeof(gbl_args));
+ if (error)
+ return error;
+ gbl_args.gbl = 0;
+ break;
+ default:
+ return EOPNOTSUPP;
+ break;
+ }
+ proc_locked = 0;
+ switch (call) {
+ case MAC_GRANTBYLABEL_FETCH_GBL:
+ error = getvnode(td, gbl_args.u.fd,
+ cap_rights_init(&rights), &fp);
+ if (error)
+ return (error);
+
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EINVAL;
+ goto cleanup_file;
+ }
+
+ vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
+ gbl_args.gbl = gbl_get_vlabel(fp->f_vnode, td->td_ucred);
+ if (gbl_args.gbl == 0)
+ error = EOPNOTSUPP;
+ else
+ error = 0;
+ VOP_UNLOCK(fp->f_vnode, 0);
+cleanup_file:
+ fdrop(fp, td);
+ break;
+ case MAC_GRANTBYLABEL_FETCH_PID_GBL:
+ error = 0;
+ if (gbl_args.u.pid == 0
+ || gbl_args.u.pid == curproc->p_pid) {
+ proc = curproc;
+ } else {
+ proc = pfind(gbl_args.u.pid);
+ if (proc == NULL)
+ return (EINVAL);
+ proc_locked = 1;
+ }
+ gbl_args.gbl = (SLOT(proc->p_textvp->v_label) |
+ SLOT(proc->p_label));
+ if (proc_locked)
+ PROC_UNLOCK(proc);
+ break;
+ }
+ if (error == 0) {
+ error = copyout(&gbl_args, arg, sizeof(gbl_args));
+ }
+ return error;
+}
+
+
+static void
+mac_grantbylabel_proc_init_label(struct label *label)
+{
+
+ SLOT_SET(label, 0); /* not yet set! */
+}
+
+static void
+mac_grantbylabel_vnode_init_label(struct label *label)
+{
+
+ SLOT_SET(label, 0); /* not yet set! */
+}
+
+/**
+ * @brief set v_label if needed
+ */
+static int
+mac_grantbylabel_vnode_check_exec(struct ucred *cred __unused,
+ struct vnode *vp __unused, struct label *label __unused,
+ struct image_params *imgp, struct label *execlabel __unused)
+{
+ gbl_label_t gbl;
+
+ gbl = SLOT(vp->v_label);
+ if (gbl == 0) {
+ gbl = gbl_get_vlabel(vp, cred);
+ if (gbl == 0)
+ gbl = GBL_EMPTY;
+ MAC_GRANTBYLABEL_DBG(1, "vnode_check_exec label=%#o", gbl);
+ SLOT_SET(vp->v_label, gbl);
+ }
+ return 0;
+}
+
+static void
+mac_grantbylabel_copy_label(struct label *src, struct label *dest)
+{
+ SLOT_SET(dest, SLOT(src));
+}
+
+/**
+ * @brief if interpreting copy script v_label to proc p_label
+ */
+static int
+mac_grantbylabel_vnode_execve_will_transition(struct ucred *old,
+ struct vnode *vp, struct label *vplabel,
+ struct label *interpvplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+ gbl_label_t gbl;
+
+ if (imgp->interpreted) {
+ gbl = SLOT(interpvplabel);
+ if (gbl) {
+ SLOT_SET(imgp->proc->p_label, gbl);
+ }
+ MAC_GRANTBYLABEL_DBG(1, "execve_will_transition label=%#o", gbl);
+ }
+ return 0;
+}
+
+
+static struct mac_policy_ops mac_grantbylabel_ops =
+{
+ .mpo_proc_check_resource = mac_grantbylabel_proc_check_resource,
+ .mpo_priv_grant = mac_grantbylabel_priv_grant,
+ .mpo_syscall = mac_grantbylabel_syscall,
+ .mpo_proc_init_label = mac_grantbylabel_proc_init_label,
+ .mpo_vnode_check_exec = mac_grantbylabel_vnode_check_exec,
+ .mpo_vnode_copy_label = mac_grantbylabel_copy_label,
+ .mpo_vnode_execve_will_transition = mac_grantbylabel_vnode_execve_will_transition,
+ .mpo_vnode_init_label = mac_grantbylabel_vnode_init_label,
+};
+
+#ifdef MAC_GRANTBYLABEL_DEBUG
+# define MAC_GRANTBYLABEL_MPC_FLAGS MPC_LOADTIME_FLAG_UNLOADOK
+#else
+# define MAC_GRANTBYLABEL_MPC_FLAGS MPC_LOADTIME_FLAG_NOTLATE
+#endif
+
+MAC_POLICY_SET(&mac_grantbylabel_ops, mac_grantbylabel, MAC_GRANTBYLABEL_FULLNAME,
+ MAC_GRANTBYLABEL_MPC_FLAGS, &mac_grantbylabel_slot);
+MODULE_VERSION(mac_grantbylabel, 1);
+MODULE_DEPEND(mac_grantbylabel, mac_veriexec, 1, 1, 1);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Oct 12, 5:40 PM (1 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23633446
Default Alt Text
D41431.id125892.diff (25 KB)
Attached To
Mode
D41431: Add mac_grantbylabel
Attached
Detach File
Event Timeline
Log In to Comment