Page MenuHomeFreeBSD

D27364.id79963.diff
No OneTemporary

D27364.id79963.diff

Index: etc/mtree/BSD.include.dist
===================================================================
--- etc/mtree/BSD.include.dist
+++ etc/mtree/BSD.include.dist
@@ -290,6 +290,8 @@
..
mac_bsdextended
..
+ mac_grantbylabel
+ ..
mac_lomac
..
mac_mls
Index: include/Makefile
===================================================================
--- include/Makefile
+++ include/Makefile
@@ -59,7 +59,9 @@
netinet/netdump \
netinet/tcp_stacks \
security/audit \
- 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 \
Index: lib/libveriexec/Makefile
===================================================================
--- lib/libveriexec/Makefile
+++ lib/libveriexec/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-.include <src.opts.mk>
+.include <bsd.own.mk>
LIB= veriexec
MAN= veriexec.3
@@ -8,7 +8,10 @@
WARNS?= 2
-SRCS= veriexec_check.c
+SRCS= \
+ exec_script.c \
+ gbl_check.c \
+ veriexec_check.c
.include <bsd.lib.mk>
Index: lib/libveriexec/exec_script.c
===================================================================
--- /dev/null
+++ 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
Index: lib/libveriexec/gbl_check.c
===================================================================
--- /dev/null
+++ lib/libveriexec/gbl_check.c
@@ -0,0 +1,89 @@
+/*
+ * 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 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) {
+ rc = gbl.gbl;
+ }
+ close(fd);
+ }
+ return(rc);
+}
+
+/**
+ * @brief does pid have a gbl label
+ *
+ * @return
+ * @li 0 if no 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) {
+ rc = gbl.gbl;
+ }
+ return(rc);
+}
Index: lib/libveriexec/libveriexec.h
===================================================================
--- lib/libveriexec/libveriexec.h
+++ lib/libveriexec/libveriexec.h
@@ -29,9 +29,14 @@
#ifndef __LIBVERIEXEC_H__
#define __LIBVERIEXEC_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_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 *);
+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
#endif /* __LIBVERIEXEC_H__ */
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3435,7 +3435,7 @@
dev/videomode/edid.c optional videomode
dev/videomode/pickmode.c optional videomode
dev/videomode/vesagtf.c optional videomode
-dev/veriexec/verified_exec.c optional veriexec mac_veriexec
+dev/veriexec/verified_exec.c optional mac_veriexec
dev/vge/if_vge.c optional vge
dev/viapm/viapm.c optional viapm pci
dev/virtio/virtio.c optional virtio
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -826,6 +826,17 @@
oldtextvp = p->p_textvp;
p->p_textvp = newtextvp;
+#ifdef MAC
+ error = mac_proc_check_resource(p->p_ucred, p);
+ if (error) {
+ if (p->p_textvp) {
+ p->p_textvp = oldtextvp;
+ oldtextvp = NULL;
+ }
+ goto exec_fail_dealloc;
+ }
+#endif
+
#ifdef KDTRACE_HOOKS
/*
* Tell the DTrace fasttrap provider about the exec if it
Index: sys/security/mac/mac_framework.h
===================================================================
--- sys/security/mac/mac_framework.h
+++ sys/security/mac/mac_framework.h
@@ -312,6 +312,7 @@
}
int mac_proc_check_debug(struct ucred *cred, struct proc *p);
+int mac_proc_check_resource(struct ucred *cred, struct proc *p);
int mac_proc_check_sched(struct ucred *cred, struct proc *p);
int mac_proc_check_signal(struct ucred *cred, struct proc *p,
int signum);
Index: sys/security/mac/mac_policy.h
===================================================================
--- sys/security/mac/mac_policy.h
+++ sys/security/mac/mac_policy.h
@@ -389,6 +389,8 @@
typedef int (*mpo_proc_check_debug_t)(struct ucred *cred,
struct proc *p);
+typedef int (*mpo_proc_check_resource_t)(struct ucred *cred,
+ struct proc *proc);
typedef int (*mpo_proc_check_sched_t)(struct ucred *cred,
struct proc *p);
typedef int (*mpo_proc_check_signal_t)(struct ucred *cred,
@@ -833,6 +835,7 @@
mpo_priv_grant_t mpo_priv_grant;
mpo_proc_check_debug_t mpo_proc_check_debug;
+ mpo_proc_check_resource_t mpo_proc_check_resource;
mpo_proc_check_sched_t mpo_proc_check_sched;
mpo_proc_check_signal_t mpo_proc_check_signal;
mpo_proc_check_wait_t mpo_proc_check_wait;
Index: sys/security/mac/mac_process.c
===================================================================
--- sys/security/mac/mac_process.c
+++ sys/security/mac/mac_process.c
@@ -431,3 +431,18 @@
return (error);
}
+
+MAC_CHECK_PROBE_DEFINE2(proc_check_resource, "struct ucred *", "struct proc *");
+
+int
+mac_proc_check_resource(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_POLICY_CHECK_NOSLEEP(proc_check_resource, cred, p);
+ MAC_CHECK_PROBE2(proc_check_resource, error, cred, p);
+
+ return (error);
+}
Index: sys/security/mac_grantbylabel/mac_grantbylabel.h
===================================================================
--- /dev/null
+++ sys/security/mac_grantbylabel/mac_grantbylabel.h
@@ -0,0 +1,66 @@
+/*
+ * $FreeBSD$
+ *
+ * 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.
+ * 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.
+ */
+
+#ifndef _SECURITY_MAC_GRANTBYLABEL_H
+#define _SECURITY_MAC_GRANTBYLABEL_H
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+#define MAC_GRANTBYLABEL_NAME "mac_grantbylabel"
+
+/* 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_MAX 8
+
+/* 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
Index: sys/security/mac_grantbylabel/mac_grantbylabel.c
===================================================================
--- /dev/null
+++ sys/security/mac_grantbylabel/mac_grantbylabel.c
@@ -0,0 +1,404 @@
+/*-
+ * $FreeBSD$
+ *
+ * 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.
+ * 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>
+
+#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/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"
+
+#ifdef MAC_GRANTBYLABEL_DEBUG
+# ifndef MAC_DEBUG
+# define MAC_DEBUG
+# endif
+# 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");
+
+#else
+# define GRANTBYLABEL_DEBUG(n, x)
+#endif
+
+#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 '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 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_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);
+
+ /*
+ * 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_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_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 */
+ case PRIV_VFS_READ:
+ case PRIV_VFS_WRITE:
+ 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)
+{
+ struct vattr va;
+ const char *label;
+ int error;
+
+ if (!SLOT(proc->p_textvp->v_label)) {
+ error = VOP_GETATTR(proc->p_textvp, &va, cred);
+ if (!error) {
+ 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);
+ SLOT_SET(proc->p_textvp->v_label,
+ (intptr_t)gbl_parse_label(label));
+ return 0;
+ }
+ }
+ SLOT_SET(proc->p_textvp->v_label,
+ (intptr_t)GBL_EMPTY);
+ }
+ 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;
+ gbl_label_t gbl;
+ struct vattr va;
+ struct file *fp;
+ struct proc *proc;
+ const char *label;
+ int error;
+
+ error = EOPNOTSUPP;
+ switch (call) {
+ case MAC_GRANTBYLABEL_FETCH_GBL:
+ gbl_args = arg;
+ gbl = 0;
+ error = getvnode(td, (uintptr_t) 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);
+ error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred);
+ if (!error) {
+ label = mac_veriexec_metadata_get_file_label(va.va_fsid,
+ va.va_fileid, va.va_gen, FALSE);
+ if (label) {
+ gbl = gbl_parse_label(label);
+ } else {
+ error = EOPNOTSUPP;
+ }
+ }
+ VOP_UNLOCK(fp->f_vnode);
+cleanup_file:
+ fdrop(fp, td);
+ break;
+ case MAC_GRANTBYLABEL_FETCH_PID_GBL:
+ gbl_args = arg;
+ gbl = 0;
+
+ /* right now we only support curproc */
+ if (gbl_args->u.pid == 0
+ || gbl_args->u.pid == curproc->p_pid) {
+ proc = curproc;
+ error = 0;
+ } else {
+ return (EINVAL);
+ }
+ gbl = SLOT(proc->p_textvp->v_label);
+ break;
+ }
+ if (error == 0) {
+ error = copyout(&gbl, &gbl_args->gbl,
+ sizeof(gbl_label_t));
+ }
+ return error;
+}
+
+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,
+};
+
+#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);
Index: sys/security/mac_veriexec/mac_veriexec.h
===================================================================
--- sys/security/mac_veriexec/mac_veriexec.h
+++ sys/security/mac_veriexec/mac_veriexec.h
@@ -157,6 +157,8 @@
int override);
int mac_veriexec_metadata_has_file(dev_t fsid, long fileid,
unsigned long gen);
+const char * mac_veriexec_metadata_get_file_label(dev_t fsid, long fileid,
+ unsigned long gen, int check_files);
int mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p);
#endif
Index: sys/security/mac_veriexec/mac_veriexec.c
===================================================================
--- sys/security/mac_veriexec/mac_veriexec.c
+++ sys/security/mac_veriexec/mac_veriexec.c
@@ -52,6 +52,7 @@
#include <sys/vnode.h>
#include <fs/nullfs/null.h>
#include <security/mac/mac_policy.h>
+#include <security/mac/mac_framework.h>
#include "mac_veriexec.h"
#include "mac_veriexec_internal.h"
@@ -529,6 +530,10 @@
return (error);
break;
default:
+ if (mac_priv_grant(cred, PRIV_VERIEXEC_NOVERIFY) == 0) {
+
+ return (0);
+ }
/*
* Caller wants open to fail unless there is a valid
* fingerprint registered.
Index: sys/security/mac_veriexec/veriexec_fingerprint.c
===================================================================
--- sys/security/mac_veriexec/veriexec_fingerprint.c
+++ sys/security/mac_veriexec/veriexec_fingerprint.c
@@ -46,6 +46,7 @@
#include <sys/sbuf.h>
#include <sys/syslog.h>
#include <sys/vnode.h>
+#include <sys/priv.h>
#include "mac_veriexec.h"
#include "mac_veriexec_internal.h"
@@ -215,7 +216,7 @@
int error;
/* reject fingerprint if writers are active */
- if (vp->v_writecount > 0)
+ if (vp->v_writecount)
return (ETXTBSY);
if ((vp->v_mount->mnt_flag & MNT_VERIFIED) != 0) {
Index: sys/security/mac_veriexec/veriexec_metadata.c
===================================================================
--- sys/security/mac_veriexec/veriexec_metadata.c
+++ sys/security/mac_veriexec/veriexec_metadata.c
@@ -138,8 +138,6 @@
break;
/* we need to garbage collect */
LIST_REMOVE(ip, entries);
- if (ip->label)
- free(ip->label, M_VERIEXEC);
free(ip, M_VERIEXEC);
}
}
@@ -584,6 +582,30 @@
}
/**
+ * Return label if we have one
+ *
+ * @param fsid file system identifier to look for
+ * @param fileid file to look for
+ * @param gen generation of file
+ * @param check_files look at non-executable files?
+ *
+ * @return A pointer to the label or @c NULL
+ */
+const char *
+mac_veriexec_metadata_get_file_label(dev_t fsid, long fileid,
+ unsigned long gen, int check_files)
+{
+ struct mac_veriexec_file_info *ip;
+
+ ip = mac_veriexec_metadata_get_file_info(fsid, fileid, gen,
+ NULL, check_files);
+ if (ip && (ip->flags & VERIEXEC_LABEL)) {
+ return ip->label;
+ }
+ return NULL;
+}
+
+/**
* Add a file and its fingerprint to the list of files attached
* to the device @p fsid.
*
Index: sys/sys/priv.h
===================================================================
--- sys/sys/priv.h
+++ sys/sys/priv.h
@@ -512,9 +512,16 @@
#define PRIV_KMEM_WRITE 681 /* Open mem/kmem for writing. */
/*
+ * veriexec override privileges - very rare!
+ */
+#define PRIV_VERIEXEC_DIRECT 700 /* Can override 'indirect' */
+#define PRIV_VERIEXEC_NOVERIFY 701 /* Can override O_VERIFY */
+
+
+/*
* Track end of privilege list.
*/
-#define _PRIV_HIGHEST 682
+#define _PRIV_HIGHEST 702
/*
* Validate that a named privilege is known by the privilege system. Invalid

File Metadata

Mime Type
text/plain
Expires
Sun, Sep 13, 9:24 AM (4 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38846357
Default Alt Text
D27364.id79963.diff (28 KB)

Event Timeline