NetBSD Problem Report #60756

From www@netbsd.org  Sun Sep 20 13:21:35 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)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.netbsd.org", Issuer "YR1" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id C111B1A923B
	for <gnats-bugs@gnats.NetBSD.org>; Sun, 20 Sep 2026 13:21:35 +0000 (UTC)
Message-Id: <20260920132134.967D91A923C@mollari.NetBSD.org>
Date: Sun, 20 Sep 2026 13:21:34 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: compat_linux inotify(2): TOCTOU and locking shenanigans
X-Send-Pr-Version: www-1.0
X-From4GNATS: "campbell+netbsd@mumble.net via gnats" <gnats-admin@NetBSD.org>

>Number:         60756
>Category:       kern
>Synopsis:       compat_linux inotify(2): TOCTOU and locking shenanigans
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          needs-pullups
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Sep 20 13:25:01 +0000 2026
>Closed-Date:    
>Last-Modified:  Fri Oct 02 03:30:36 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10, ...
>Organization:
The CompatBSD Inotification, Inc.
>Environment:
>Description:

	inotify_readdir sometimes runs with the vnode lock, and
	sometimes unlocks and relocks the interlock, which strikes
	me as incoherent and likely fundamentally buggy:

    790 	/* XXX: should pass whether to lock or not */
    791 	if (needs_lock)
    792 		vn_lock(vp, LK_SHARED | LK_RETRY);
    793 	else
    794 		/*
    795 		 * XXX We need to temporarily drop v_interlock because
    796 		 * it may be temporarily acquired by biowait().
    797 		 */
    798 		mutex_exit(vp->v_interlock);
    799 	KASSERT(!mutex_owned(vp->v_interlock));
    800 	error = VOP_READDIR(vp, &uio, fp->f_cred, &eofflag, NULL, NULL);
    801 	if (needs_lock)
    802 		VOP_UNLOCK(vp);
    803 	else
    804 		mutex_enter(vp->v_interlock);

	https://nxr.netbsd.org/xref/src/sys/compat/linux/common/linux_inotify.c?r=1.8#761

	It is not clear to me whether in the needs_lock=false case it
	actually holds the vnode lock.  This should be asserted.

	The needs_lock=true case used by get_inotify_dir_entries
	creates a TOCTOU issue: in one pass, it it counts the number of
	entries with inotify_readdir; in a second pass, it copies them
	into an array of that many entries -- but the number of entries
	may have changed between the first pass and the second pass
	(with some large entries being split into multiple small ones),
	possibly leading the inner while loop in the second pass to
	walk off the end of the array.

    842 	mutex_enter(&wp->f_lock);
    843 	wp->f_offset = 0;
    844 	mutex_exit(&wp->f_lock);
    845 	decount = 0;
    846 	for (;;) {
    847 		error = inotify_readdir(wp, &de, &done, needs_lock);
    848 		if (error != 0)
    849 			goto leave;
    850 		if (done == 0)
    851 			break;
    852 
    853 		currdep = &de;
    854 	        while ((char *)currdep < ((char *)&de) + done) {
    855 			decount++;
    856 			currdep = _DIRENT_NEXT(currdep);
    857 		}
    858 	}
    859 
    860 	idep = kmem_zalloc(INOTIFY_DIR_ENTRIES_SIZE(decount), KM_SLEEP);
    861 	idep->ide_count = decount;
    862 
    863 	mutex_enter(&wp->f_lock);
    864 	wp->f_offset = 0;
    865 	mutex_exit(&wp->f_lock);
    866 	for (i = 0; i < decount;) {
    867 		error = inotify_readdir(wp, &de, &done, needs_lock);
    868 		if (error != 0 || done == 0) {
    869 			kmem_free(idep, INOTIFY_DIR_ENTRIES_SIZE(decount));
    870 			idep = NULL;
    871 			goto leave;
    872 		}
    873 
    874 		currdep = &de;
    875 		while ((char *)currdep < ((char *)&de) + done) {
    876 			idep->ide_entries[i].fileno = currdep->d_fileno;
    877 			strcpy(idep->ide_entries[i].name, currdep->d_name);
    878 
    879 			currdep = _DIRENT_NEXT(currdep);
    880 			i++;
    881 		}
    882 	}

	https://nxr.netbsd.org/xref/src/sys/compat/linux/common/linux_inotify.c?r=1.8#842

>How-To-Repeat:

	code inspection

>Fix:

	1. At least bound the inner while loop in the second pass of
	   get_inotify_dir_entries.

	2. Fix the locking shenanigans.

	3. Nix strcpy while here; use strlcpy, strncpy, or copystr
	   instead, depending on the nature of the input and output
	   buffers.

>Release-Note:

>Audit-Trail:
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60756 CVS commit: src/sys/compat/linux/common
Date: Sun, 20 Sep 2026 13:47:39 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Sep 20 13:47:39 UTC 2026

 Modified Files:
 	src/sys/compat/linux/common: linux_inotify.c

 Log Message:
 compat_linux inotify(2): strcpy -> strlcpy

 PR kern/60756: compat_linux inotify(2): TOCTOU and locking shenanigans


 To generate a diff of this commit:
 cvs rdiff -u -r1.9 -r1.10 src/sys/compat/linux/common/linux_inotify.c

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

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60756 CVS commit: src/sys/compat/linux/common
Date: Sun, 20 Sep 2026 13:48:00 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Sep 20 13:48:00 UTC 2026

 Modified Files:
 	src/sys/compat/linux/common: linux_inotify.c

 Log Message:
 compat_linux inotify(2): Re-check number of entries in loop.

 Might have changed between two calls to inotify_readdir.

 XXX Should maybe not do two calls to inotify_readdir!  Can we hold
 the vnode lock or use a fixed temporary buffer size or something?

 PR kern/60756: compat_linux inotify(2): TOCTOU and locking shenanigans


 To generate a diff of this commit:
 cvs rdiff -u -r1.10 -r1.11 src/sys/compat/linux/common/linux_inotify.c

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

State-Changed-From-To: open->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Fri, 02 Oct 2026 03:30:36 +0000
State-Changed-Why:
partly fixed in HEAD, needs pullup-11 and pullup-10

...then back to open to fix the lock shenanigans and underlying TOCTOU
issue


>Unformatted:

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.