git: 2449b9e5fe56 - main - mac: kdb/ddb framework hooks

From: Allan Jude <allanjude_at_FreeBSD.org>
Date: Mon, 18 Jul 2022 22:06:55 UTC
The branch main has been updated by allanjude:

URL: https://cgit.FreeBSD.org/src/commit/?id=2449b9e5fe565be757a4b29093fd1c9c6ffcf3c9

commit 2449b9e5fe565be757a4b29093fd1c9c6ffcf3c9
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2022-07-18 21:23:16 +0000
Commit:     Allan Jude <allanjude@FreeBSD.org>
CommitDate: 2022-07-18 22:06:13 +0000

    mac: kdb/ddb framework hooks
    
    Add three simple hooks to the debugger allowing for a loaded MAC policy
    to intervene if desired:
     1. Before invoking the kdb backend
     2. Before ddb command registration
     3. Before ddb command execution
    
    We extend struct db_command with a private pointer and two flag bits
    reserved for policy use.
    
    Reviewed by:    markj
    Sponsored by:   Juniper Networks, Inc.
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D35370
---
 sys/conf/files                   |  1 +
 sys/ddb/db_command.c             | 16 ++++++++++
 sys/ddb/ddb.h                    |  3 ++
 sys/kern/subr_kdb.c              | 11 +++++++
 sys/security/mac/mac_framework.h | 10 ++++++
 sys/security/mac/mac_kdb.c       | 69 ++++++++++++++++++++++++++++++++++++++++
 sys/security/mac/mac_policy.h    | 17 ++++++++++
 sys/security/mac_stub/mac_stub.c | 31 ++++++++++++++++++
 sys/security/mac_test/mac_test.c | 39 +++++++++++++++++++++++
 9 files changed, 197 insertions(+)

diff --git a/sys/conf/files b/sys/conf/files
index 30cd9eb7e741..4e1279adc073 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -5118,6 +5118,7 @@ security/audit/bsm_socket_type.c	optional audit
 security/audit/bsm_token.c	optional audit
 security/mac/mac_audit.c	optional mac audit
 security/mac/mac_cred.c		optional mac
+security/mac/mac_kdb.c		optional mac
 security/mac/mac_framework.c	optional mac
 security/mac/mac_inet.c		optional mac inet | mac inet6
 security/mac/mac_inet6.c	optional mac inet6
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
index 71e9b039d7a9..ab7bec8f2ffc 100644
--- a/sys/ddb/db_command.c
+++ b/sys/ddb/db_command.c
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpu.h>
 #include <machine/setjmp.h>
 
+#include <security/mac/mac_framework.h>
+
 /*
  * Exported global variables
  */
@@ -236,6 +238,13 @@ db_command_register(struct db_command_table *list, struct db_command *cmd)
 {
 	struct db_command *c, *last;
 
+#ifdef MAC
+	if (mac_ddb_command_register(list, cmd)) {
+		printf("%s: MAC policy refused registration of command %s\n",
+		    __func__, cmd->name);
+		return;
+	}
+#endif
 	last = NULL;
 	LIST_FOREACH(c, list, next) {
 		int n = strcmp(cmd->name, c->name);
@@ -480,6 +489,13 @@ db_command(struct db_command **last_cmdp, struct db_command_table *cmd_table,
 
 	*last_cmdp = cmd;
 	if (cmd != NULL) {
+#ifdef MAC
+		if (mac_ddb_command_exec(cmd, addr, have_addr, count, modif)) {
+			db_printf("MAC prevented execution of command %s\n",
+			    cmd->name);
+			return;
+		}
+#endif
 		/*
 		 * Execute the command.
 		 */
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index dce4e80ac117..4c8a4f165461 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -119,8 +119,11 @@ struct db_command {
 #define	CS_SET_DOT	0x100	/* set dot after command */
 #define	DB_CMD_MEMSAFE	0x1000	/* Command does not allow reads or writes to
 				 * arbitrary memory. */
+#define	DB_MAC1		0x10000	/* For MAC policy use */
+#define	DB_MAC2		0x20000
 	struct db_command_table *more; /* another level of command */
 	LIST_ENTRY(db_command) next; /* next entry in the command table */
+	void *mac_priv;		/* For MAC policy use */
 };
 
 /*
diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c
index 6aa8bd17e048..b1bf197be3dc 100644
--- a/sys/kern/subr_kdb.c
+++ b/sys/kern/subr_kdb.c
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/smp.h>
 #endif
 
+#include <security/mac/mac_framework.h>
+
 u_char __read_frequently kdb_active = 0;
 static void *kdb_jmpbufp = NULL;
 struct kdb_dbbe *kdb_dbbe = NULL;
@@ -731,6 +733,15 @@ kdb_trap(int type, int code, struct trapframe *tf)
 	cngrab();
 
 	for (;;) {
+#ifdef MAC
+		if (mac_kdb_check_backend(be) != 0) {
+			printf("MAC prevented execution of KDB backend: %s\n",
+			    be->dbbe_name);
+			/* Unhandled breakpoint traps are fatal. */
+			handled = 1;
+			break;
+		}
+#endif
 		handled = be->dbbe_trap(type, code);
 		if (be == kdb_dbbe)
 			break;
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
index 7a46fbedb28d..78a991fe10fe 100644
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -65,6 +65,7 @@ struct image_params;
 struct inpcb;
 struct ip6q;
 struct ipq;
+struct kdb_dbbe;
 struct ksem;
 struct label;
 struct m_tag;
@@ -92,6 +93,8 @@ struct vop_setlabel_args;
 #include <sys/acl.h>			/* XXX acl_type_t */
 #include <sys/types.h>			/* accmode_t */
 
+#include <ddb/ddb.h>			/* db_expr_t */
+
 /*
  * Entry points to the TrustedBSD MAC Framework from the remainder of the
  * kernel: entry points are named based on a principle object type and an
@@ -130,6 +133,11 @@ void	mac_cred_create_swapper(struct ucred *cred);
 void	mac_cred_destroy(struct ucred *);
 void	mac_cred_init(struct ucred *);
 
+int	mac_ddb_command_register(struct db_command_table *table,
+	    struct db_command *cmd);
+int	mac_ddb_command_exec(struct db_command *cmd, db_expr_t addr,
+	    bool have_addr, db_expr_t count, char *modif);
+
 void	mac_devfs_create_device(struct ucred *cred, struct mount *mp,
 	    struct cdev *dev, struct devfs_dirent *de);
 void	mac_devfs_create_directory(struct mount *mp, char *dirname,
@@ -205,6 +213,8 @@ int	mac_ipq_match(struct mbuf *m, struct ipq *q);
 void	mac_ipq_reassemble(struct ipq *q, struct mbuf *m);
 void	mac_ipq_update(struct mbuf *m, struct ipq *q);
 
+int	mac_kdb_check_backend(struct kdb_dbbe *be);
+
 int	mac_kenv_check_dump(struct ucred *cred);
 int	mac_kenv_check_get(struct ucred *cred, char *name);
 int	mac_kenv_check_set(struct ucred *cred, char *name, char *value);
diff --git a/sys/security/mac/mac_kdb.c b/sys/security/mac/mac_kdb.c
new file mode 100644
index 000000000000..9082ec7d4580
--- /dev/null
+++ b/sys/security/mac/mac_kdb.c
@@ -0,0 +1,69 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2022 Klara Systems
+ *
+ * This software was developed by Mitchell Horne <mhorne@FreeBSD.org>
+ * under sponsorship from Juniper Networks and Klara Systems.
+ *
+ * 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 "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <ddb/ddb.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+int
+mac_kdb_check_backend(struct kdb_dbbe *be)
+{
+	int error = 0;
+
+	MAC_POLICY_CHECK_NOSLEEP(kdb_check_backend, be);
+	return (error);
+}
+
+int
+mac_ddb_command_register(struct db_command_table *table, struct db_command *cmd)
+{
+	int error = 0;
+
+	MAC_POLICY_CHECK_NOSLEEP(ddb_command_register, table, cmd);
+	return (error);
+}
+
+int
+mac_ddb_command_exec(struct db_command *cmd, db_expr_t addr,
+    bool have_addr, db_expr_t count, char *modif)
+{
+	int error = 0;
+
+	MAC_POLICY_CHECK_NOSLEEP(ddb_command_exec, cmd, addr, have_addr,
+	    count, modif);
+	return (error);
+}
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
index b875e6eb5487..97b3522abf51 100644
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -66,18 +66,22 @@
 #include <sys/acl.h>	/* XXX acl_type_t */
 #include <sys/types.h>	/* XXX accmode_t */
 
+#include <ddb/ddb.h>	/* XXX db_expr_t */
+
 struct acl;
 struct auditinfo;
 struct auditinfo_addr;
 struct bpf_d;
 struct cdev;
 struct componentname;
+struct db_command;
 struct devfs_dirent;
 struct ifnet;
 struct image_params;
 struct inpcb;
 struct ip6q;
 struct ipq;
+struct kdb_dbbe;
 struct ksem;
 struct label;
 struct mac_policy_conf;
@@ -168,6 +172,12 @@ typedef int	(*mpo_cred_internalize_label_t)(struct label *label,
 typedef void	(*mpo_cred_relabel_t)(struct ucred *cred,
 		    struct label *newlabel);
 
+typedef int	(*mpo_ddb_command_register_t)(struct db_command_table *table,
+		    struct db_command *cmd);
+typedef int	(*mpo_ddb_command_exec_t)(struct db_command *cmd,
+		    db_expr_t addr, bool have_addr, db_expr_t count,
+		    char *modif);
+
 typedef void	(*mpo_devfs_create_device_t)(struct ucred *cred,
 		    struct mount *mp, struct cdev *dev,
 		    struct devfs_dirent *de, struct label *delabel);
@@ -249,6 +259,8 @@ typedef void	(*mpo_ipq_reassemble)(struct ipq *q, struct label *qlabel,
 typedef void	(*mpo_ipq_update_t)(struct mbuf *m, struct label *mlabel,
 		    struct ipq *q, struct label *qlabel);
 
+typedef int	(*mpo_kdb_check_backend_t)(struct kdb_dbbe *be);
+
 typedef int	(*mpo_kenv_check_dump_t)(struct ucred *cred);
 typedef int	(*mpo_kenv_check_get_t)(struct ucred *cred, char *name);
 typedef int	(*mpo_kenv_check_set_t)(struct ucred *cred, char *name,
@@ -720,6 +732,9 @@ struct mac_policy_ops {
 	mpo_cred_internalize_label_t		mpo_cred_internalize_label;
 	mpo_cred_relabel_t			mpo_cred_relabel;
 
+	mpo_ddb_command_register_t		mpo_ddb_command_register;
+	mpo_ddb_command_exec_t			mpo_ddb_command_exec;
+
 	mpo_devfs_create_device_t		mpo_devfs_create_device;
 	mpo_devfs_create_directory_t		mpo_devfs_create_directory;
 	mpo_devfs_create_symlink_t		mpo_devfs_create_symlink;
@@ -761,6 +776,8 @@ struct mac_policy_ops {
 	mpo_ipq_reassemble			mpo_ipq_reassemble;
 	mpo_ipq_update_t			mpo_ipq_update;
 
+	mpo_kdb_check_backend_t			mpo_kdb_check_backend;
+
 	mpo_kenv_check_dump_t			mpo_kenv_check_dump;
 	mpo_kenv_check_get_t			mpo_kenv_check_get;
 	mpo_kenv_check_set_t			mpo_kenv_check_set;
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
index 8174345f073a..6b32408b92fe 100644
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -54,6 +54,7 @@
 #include <sys/acl.h>
 #include <sys/conf.h>
 #include <sys/extattr.h>
+#include <sys/kdb.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
 #include <sys/mount.h>
@@ -72,6 +73,8 @@
 #include <sys/sem.h>
 #include <sys/shm.h>
 
+#include <ddb/ddb.h>
+
 #include <fs/devfs/devfs.h>
 
 #include <net/bpfdesc.h>
@@ -314,6 +317,22 @@ stub_cred_relabel(struct ucred *cred, struct label *newlabel)
 
 }
 
+static int
+stub_ddb_command_exec(struct db_command *cmd, db_expr_t addr, bool have_addr,
+    db_expr_t count, char *modif)
+{
+
+	return (0);
+}
+
+static int
+stub_ddb_command_register(struct db_command_table *table,
+    struct db_command *cmd)
+{
+
+	return (0);
+}
+
 static void
 stub_devfs_create_device(struct ucred *cred, struct mount *mp,
     struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
@@ -476,6 +495,13 @@ stub_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
 
 }
 
+static int
+stub_kdb_check_backend(struct kdb_dbbe *be)
+{
+
+	return (0);
+}
+
 static int
 stub_kenv_check_dump(struct ucred *cred)
 {
@@ -1685,6 +1711,9 @@ static struct mac_policy_ops stub_ops =
 	.mpo_cred_internalize_label = stub_internalize_label,
 	.mpo_cred_relabel= stub_cred_relabel,
 
+	.mpo_ddb_command_exec = stub_ddb_command_exec,
+	.mpo_ddb_command_register = stub_ddb_command_register,
+
 	.mpo_devfs_create_device = stub_devfs_create_device,
 	.mpo_devfs_create_directory = stub_devfs_create_directory,
 	.mpo_devfs_create_symlink = stub_devfs_create_symlink,
@@ -1726,6 +1755,8 @@ static struct mac_policy_ops stub_ops =
 	.mpo_ipq_update = stub_ipq_update,
 	.mpo_ipq_reassemble = stub_ipq_reassemble,
 
+	.mpo_kdb_check_backend = stub_kdb_check_backend,
+
 	.mpo_kenv_check_dump = stub_kenv_check_dump,
 	.mpo_kenv_check_get = stub_kenv_check_get,
 	.mpo_kenv_check_set = stub_kenv_check_set,
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
index 12291fbd37d9..48c8fe782909 100644
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -69,6 +69,8 @@
 #include <sys/sx.h>
 #include <sys/sysctl.h>
 
+#include <ddb/ddb.h>
+
 #include <fs/devfs/devfs.h>
 
 #include <net/bpfdesc.h>
@@ -453,6 +455,28 @@ test_cred_relabel(struct ucred *cred, struct label *newlabel)
 	COUNTER_INC(cred_relabel);
 }
 
+COUNTER_DECL(ddb_command_exec);
+static int
+test_ddb_command_exec(struct db_command *cmd, db_expr_t addr, bool have_addr,
+    db_expr_t count, char *modif)
+{
+
+	COUNTER_INC(ddb_command_exec);
+
+	return (0);
+}
+
+COUNTER_DECL(ddb_command_register);
+static int
+test_ddb_command_register(struct db_command_table *table,
+    struct db_command *cmd)
+{
+
+	COUNTER_INC(ddb_command_register);
+
+	return (0);
+}
+
 COUNTER_DECL(devfs_create_device);
 static void
 test_devfs_create_device(struct ucred *cred, struct mount *mp,
@@ -868,6 +892,16 @@ test_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
 	COUNTER_INC(ipq_update);
 }
 
+COUNTER_DECL(kdb_backend_check);
+static int
+test_kdb_check_backend(struct kdb_dbbe *be)
+{
+
+	COUNTER_INC(kdb_backend_check);
+
+	return (0);
+}
+
 COUNTER_DECL(kenv_check_dump);
 static int
 test_kenv_check_dump(struct ucred *cred)
@@ -3022,6 +3056,9 @@ static struct mac_policy_ops test_ops =
 	.mpo_cred_internalize_label = test_cred_internalize_label,
 	.mpo_cred_relabel = test_cred_relabel,
 
+	.mpo_ddb_command_exec = test_ddb_command_exec,
+	.mpo_ddb_command_register = test_ddb_command_register,
+
 	.mpo_devfs_create_device = test_devfs_create_device,
 	.mpo_devfs_create_directory = test_devfs_create_directory,
 	.mpo_devfs_create_symlink = test_devfs_create_symlink,
@@ -3078,6 +3115,8 @@ static struct mac_policy_ops test_ops =
 	.mpo_ipq_reassemble = test_ipq_reassemble,
 	.mpo_ipq_update = test_ipq_update,
 
+	.mpo_kdb_check_backend = test_kdb_check_backend,
+
 	.mpo_kenv_check_dump = test_kenv_check_dump,
 	.mpo_kenv_check_get = test_kenv_check_get,
 	.mpo_kenv_check_set = test_kenv_check_set,