git: de2b94228075 - main - arm64: validate breakpoint registers

Mitchell Horne mhorne at FreeBSD.org
Wed Feb 17 16:07:37 UTC 2021


The branch main has been updated by mhorne:

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

commit de2b9422807586d376ec7ffa7b660cd492464bdf
Author:     Mitchell Horne <mhorne at FreeBSD.org>
AuthorDate: 2021-02-09 18:29:38 +0000
Commit:     Mitchell Horne <mhorne at FreeBSD.org>
CommitDate: 2021-02-17 16:05:00 +0000

    arm64: validate breakpoint registers
    
    In particular, we want to disallow setting breakpoints on kernel
    addresses from userspace. The control register fields are validated or
    ignored as appropriate.
    
    Reviewed by:    markj
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D28560
---
 sys/arm64/arm64/machdep.c  | 37 +++++++++++++++++++++++++++++++++----
 sys/arm64/include/armreg.h | 17 +++++++++++++++++
 2 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 90fc19d57415..bf44dba19482 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -357,6 +357,8 @@ int
 set_dbregs(struct thread *td, struct dbreg *regs)
 {
 	struct debug_monitor_state *monitor;
+	uint64_t addr;
+	uint32_t ctrl;
 	int count;
 	int i;
 
@@ -364,11 +366,38 @@ set_dbregs(struct thread *td, struct dbreg *regs)
 	count = 0;
 	monitor->dbg_enable_count = 0;
 	for (i = 0; i < DBG_BRP_MAX; i++) {
-		/* TODO: Check these values */
-		monitor->dbg_bvr[i] = regs->db_regs[i].dbr_addr;
-		monitor->dbg_bcr[i] = regs->db_regs[i].dbr_ctrl;
-		if ((monitor->dbg_bcr[i] & 1) != 0)
+		addr = regs->db_regs[i].dbr_addr;
+		ctrl = regs->db_regs[i].dbr_ctrl;
+
+		/* Don't let the user set a breakpoint on a kernel address. */
+		if (addr >= VM_MAXUSER_ADDRESS)
+			return (EINVAL);
+
+		/*
+		 * The lowest 2 bits are ignored, so record the effective
+		 * address.
+		 */
+		addr = rounddown2(addr, 4);
+
+		/*
+		 * Some control fields are ignored, and other bits reserved.
+		 * Only unlinked, address-matching breakpoints are supported.
+		 *
+		 * XXX: fields that appear unvalidated, such as BAS, have
+		 * constrained undefined behaviour. If the user mis-programs
+		 * these, there is no risk to the system.
+		 */
+		ctrl &= DBG_BCR_EN | DBG_BCR_PMC | DBG_BCR_BAS;
+		if ((ctrl & DBG_BCR_EN) != 0) {
+			/* Only target EL0. */
+			if ((ctrl & DBG_BCR_PMC) != DBG_BCR_PMC_EL0)
+				return (EINVAL);
+
 			monitor->dbg_enable_count++;
+		}
+
+		monitor->dbg_bvr[i] = addr;
+		monitor->dbg_bcr[i] = ctrl;
 	}
 	if (monitor->dbg_enable_count > 0)
 		monitor->dbg_flags |= DBGMON_ENABLED;
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index f5d25a572466..f2bce02782ec 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -944,6 +944,23 @@
 #define	DBG_MDSCR_KDE	(0x1 << 13)
 #define	DBG_MDSCR_MDE	(0x1 << 15)
 
+/* Debug Breakpoint Control Registers */
+#define	DBG_BCR_EN		0x1
+#define	DBG_BCR_PMC_SHIFT	1
+#define	DBG_BCR_PMC		(0x3 << DBG_BCR_PMC_SHIFT)
+#define	 DBG_BCR_PMC_EL1	(0x1 << DBG_BCR_PMC_SHIFT)
+#define	 DBG_BCR_PMC_EL0	(0x2 << DBG_BCR_PMC_SHIFT)
+#define	DBG_BCR_BAS_SHIFT	5
+#define	DBG_BCR_BAS		(0xf << DBG_BCR_BAS_SHIFT)
+#define	DBG_BCR_HMC_SHIFT	13
+#define	DBG_BCR_HMC		(0x1 << DBG_BCR_HMC_SHIFT)
+#define	DBG_BCR_SSC_SHIFT	14
+#define	DBG_BCR_SSC		(0x3 << DBG_BCR_SSC_SHIFT)
+#define	DBG_BCR_LBN_SHIFT	16
+#define	DBG_BCR_LBN		(0xf << DBG_BCR_LBN_SHIFT)
+#define	DBG_BCR_BT_SHIFT	20
+#define	DBG_BCR_BT		(0xf << DBG_BCR_BT_SHIFT)
+
 /* Perfomance Monitoring Counters */
 #define	PMCR_E		(1 << 0) /* Enable all counters */
 #define	PMCR_P		(1 << 1) /* Reset all counters */


More information about the dev-commits-src-main mailing list