NetBSD Problem Report #60035

From www@netbsd.org  Wed Feb 25 01:51:54 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
	 client-signature RSA-PSS (2048 bits) client-digest SHA256)
	(Client CN "mail.netbsd.org", Issuer "R13" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 83AC01A9239
	for <gnats-bugs@gnats.NetBSD.org>; Wed, 25 Feb 2026 01:51:54 +0000 (UTC)
Message-Id: <20260225015153.58FF71A923C@mollari.NetBSD.org>
Date: Wed, 25 Feb 2026 01:51:53 +0000 (UTC)
From: matthias@d2ux.net
Reply-To: matthias@d2ux.net
To: gnats-bugs@NetBSD.org
Subject: CTLFLAG_PRIVATE can be bypassed for sysctl nodes with custom handlers in sysctl_dispatch()
X-Send-Pr-Version: www-1.0
X-From4GNATS: "matthias@d2ux.net via gnats" <gnats-admin@NetBSD.org>

>Number:         60035
>Category:       kern
>Synopsis:       CTLFLAG_PRIVATE can be bypassed for sysctl nodes with custom handlers in sysctl_dispatch()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Feb 25 01:55:00 +0000 2026
>Last-Modified:  Sat Feb 28 15:50:00 +0000 2026
>Originator:     Matthias Petermann
>Release:        10.1_STABLE
>Organization:
>Environment:
NetBSD vhost.lan 10.1_STABLE NetBSD 10.1_STABLE (GENERIC) #0: Tue Feb 24 23:08:59 CET 2026  mpeterma@builder.lan:/u/sysbuild/obj/sys/arch/amd64/compile/GENERIC amd64

>Description:
Overview / motivation:
----------------------

I am trying to harden kernel message buffer access. In loginit(), I marked both kern.msgbufsize and kern.msgbuf as private (CTLFLAG_PERMANENT | CTLFLAG_PRIVATE).

In addition, in a custom jail secmodel, I deny KAUTH_REQ_SYSTEM_SYSCTL_PRVT from jail context to block private sysctl reads (including kern.msgbuf).

Despite that, dmesg still succeeds in scenarios where access should be denied.

Observed behavior:
------------------

dmesg reads the message buffer via sysctl(CTL_KERN, KERN_MSGBUF), and the sysctl calls return success even when private-node access should be blocked by policy.

Expected behavior:
------------------

Any read of a CTLFLAG_PRIVATE node should consistently require successful KAUTH_REQ_SYSTEM_SYSCTL_PRVT authorization, regardless of whether the node is served by sysctl_lookup() or by a custom sysctl_func handler.

>How-To-Repeat:
Root cause analysis:
--------------------

1. sysctl_dispatch() resolves the node via sysctl_locate().

2. If the resolved node has sysctl_func, dispatch calls that handler directly; it does not go through sysctl_lookup().

3. The strict final-node private authorization check is in sysctl_lookup() (rnode->sysctl_flags & CTLFLAG_PRIVATE => kauth_authorize_system(...SYSCTL_PRVT...)).

4. Therefore, for custom-handler nodes, final-node private enforcement can be skipped unless explicitly re-checked in dispatch.

5. kern.msgbuf/kern.msgbufsize are exactly such custom-handler nodes (sysctl_msgbuf), so they are affected by this gap.


>Fix:
In sysctl_dispatch(), after sysctl_locate() succeeds and before invoking a custom sysctl_func, perform a final target-node private authorization check equivalent to sysctl_lookup()’s check. This makes CTLFLAG_PRIVATE semantics consistent across both generic and custom-handler nodes.

---

diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 51a125541fbd423c33e8b32960ab152e09b7443a..7db8f660840f0b7160570a51f5ace971eefb516a 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -380,50 +380,59 @@ sysctl_relock(void)

 /*
  * ********************************************************************
  * the main sysctl dispatch routine.  scans the given tree and picks a
  * function to call based on what it finds.
  * ********************************************************************
  */
 int
 sysctl_dispatch(SYSCTLFN_ARGS)
 {
 	int error;
 	sysctlfn fn;
 	int ni;

 	KASSERT(rw_lock_held(&sysctl_treelock));

 	if (rnode && SYSCTL_VERS(rnode->sysctl_flags) != SYSCTL_VERSION) {
 		printf("sysctl_dispatch: rnode %p wrong version\n", rnode);
 		error = EINVAL;
 		goto out;
 	}

 	fn = NULL;
 	error = sysctl_locate(l, name, namelen, &rnode, &ni);

+	/*
+	 * Enforce private-node read permissions on the final target even when
+	 * dispatching through a custom sysctl handler rather than sysctl_lookup().
+	 */
+	if (error == 0 && l != NULL && (rnode->sysctl_flags & CTLFLAG_PRIVATE) &&
+	    (error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_SYSCTL,
+	    KAUTH_REQ_SYSTEM_SYSCTL_PRVT, NULL, NULL, NULL)) != 0)
+		goto out;
+
 	if (rnode->sysctl_func != NULL) {
 		/*
 		 * the node we ended up at has a function, so call it.  it can
 		 * hand off to query or create if it wants to.
 		 */
 		fn = rnode->sysctl_func;
 	} else if (error == 0) {
 		/*
 		 * we found the node they were looking for, so do a lookup.
 		 */
 		fn = (sysctlfn)sysctl_lookup; /* XXX may write to rnode */
 	} else if (error == ENOENT && (ni + 1) == namelen && name[ni] < 0) {
 		/*
 		 * prospective parent node found, but the terminal node was
 		 * not.  generic operations associate with the parent.
 		 */
 		switch (name[ni]) {
 		case CTL_QUERY:
 			fn = sysctl_query;
 			break;
 		case CTL_CREATE:
 #if NKSYMS > 0
 		case CTL_CREATESYM:
 #endif /* NKSYMS > 0 */
 			if (newp == NULL) {

>Audit-Trail:
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60035 CVS commit: src/sys/kern
Date: Sat, 28 Feb 2026 10:46:17 -0500

 Module Name:	src
 Committed By:	christos
 Date:		Sat Feb 28 15:46:17 UTC 2026

 Modified Files:
 	src/sys/kern: kern_sysctl.c

 Log Message:
 PR/60035: Matthias Petermann: CTLFLAG_PRIVATE can be bypassed for sysctl nodes
 with custom handlers in sysctl_dispatch()


 To generate a diff of this commit:
 cvs rdiff -u -r1.272 -r1.273 src/sys/kern/kern_sysctl.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.