Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 6 Sep 2023 14:01:33 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 8527bb2aee6c - main - dtrace: Fix a kernel panic in printm()
Message-ID:  <202309061401.386E1X2p030800@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj:

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

commit 8527bb2aee6ca9013c34445de88217a954b6628d
Author:     Domagoj Stolfa <domagoj.stolfa@gmail.com>
AuthorDate: 2023-09-06 13:25:00 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-09-06 14:00:59 +0000

    dtrace: Fix a kernel panic in printm()
    
    When using printm(), one should always pass a scratch pointer to it.
    This is achieved by calling printm with memref
    
      BEGIN { printm(fixed_len, memref(ptr, var_len)); }
    
    which will return a pointer to the DTrace scratch space of size
    sizeof(uintptr_t) * 2. However, one can easily call printm() as follows
    
      BEGIN { printm(10, (void *)NULL); }
    
    and panic the kernel as a result. This commit does two things:
    
      (1) adds a new macro DTRACE_INSCRATCHPTR(mstate, ptr, howmany) which
          checks if a certain pointer is in the DTrace scratch space;
      (2) uses DTRACE_INSCRATCHPTR() to implement a check on printm()'s DIFO
          return value in order to avoid the panic and sets CPU_DTRACE_BADADDR
          if the address is not in the scratch space.
    
    Reviewed by:    markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D41722
---
 .../contrib/opensolaris/uts/common/dtrace/dtrace.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index 02a95bfab726..ce02676e0dc1 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -515,6 +515,11 @@ do {									\
 	((mstate)->dtms_scratch_base + (mstate)->dtms_scratch_size - \
 	(mstate)->dtms_scratch_ptr >= (alloc_sz))
 
+#define DTRACE_INSCRATCHPTR(mstate, ptr, howmany) \
+	((ptr) >= (mstate)->dtms_scratch_base && \
+	(ptr) <= \
+	((mstate)->dtms_scratch_base + (mstate)->dtms_scratch_size - (howmany)))
+
 #define	DTRACE_LOADFUNC(bits)						\
 /*CSTYLED*/								\
 uint##bits##_t								\
@@ -7739,9 +7744,24 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
 			}
 
 			case DTRACEACT_PRINTM: {
-				/* The DIF returns a 'memref'. */
+				/*
+				 * printm() assumes that the DIF returns a
+				 * pointer returned by memref(). memref() is a
+				 * subroutine that is used to get around the
+				 * single-valued returns of DIF and is assumed
+				 * to always be allocated in the scratch space.
+				 * Therefore, we need to validate that the
+				 * pointer given to printm() is in the scratch
+				 * space in order to avoid a potential panic.
+				 */
 				uintptr_t *memref = (uintptr_t *)(uintptr_t) val;
 
+				if (!DTRACE_INSCRATCHPTR(&mstate,
+				    (uintptr_t)memref, 2 * sizeof(uintptr_t))) {
+					*flags |= CPU_DTRACE_BADADDR;
+					continue;
+				}
+
 				/* Get the size from the memref. */
 				size = memref[1];
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202309061401.386E1X2p030800>