Module Name:    src
Committed By:   maxv
Date:           Thu Dec 27 07:56:43 UTC 2018

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

Log Message:
Fix apparent race.

We're doing a LIST_FOREACH, but unlock filelist_lock in the middle of the
loop and drop the reference to fp. We then read fp->...le_next, but it
may have been freed by another thread.

This is difficult to trigger and observe, probably only KASAN can see
problems of this kind.

Switch to LIST_FOREACH_SAFE, and re-fetch np after re-locking.

May fix PR/53674.


To generate a diff of this commit:
cvs rdiff -u -r1.105 -r1.106 src/sys/kern/uipc_domain.c

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

Modified files:

Index: src/sys/kern/uipc_domain.c
diff -u src/sys/kern/uipc_domain.c:1.105 src/sys/kern/uipc_domain.c:1.106
--- src/sys/kern/uipc_domain.c:1.105	Sat Nov 24 17:16:44 2018
+++ src/sys/kern/uipc_domain.c	Thu Dec 27 07:56:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_domain.c,v 1.105 2018/11/24 17:16:44 maxv Exp $	*/
+/*	$NetBSD: uipc_domain.c,v 1.106 2018/12/27 07:56:43 maxv Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.105 2018/11/24 17:16:44 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.106 2018/12/27 07:56:43 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -534,7 +534,7 @@ sysctl_dounpcb(struct kinfo_pcb *pcb, co
 static int
 sysctl_unpcblist(SYSCTLFN_ARGS)
 {
-	struct file *fp, *dfp;
+	struct file *fp, *np, *dfp;
 	struct socket *so;
 	struct kinfo_pcb pcb;
 	char *dp;
@@ -583,7 +583,7 @@ sysctl_unpcblist(SYSCTLFN_ARGS)
 	 * to walk the file list looking for them.  :-/
 	 */
 	mutex_enter(&filelist_lock);
-	LIST_FOREACH(fp, &filehead, f_list) {
+	LIST_FOREACH_SAFE(fp, &filehead, f_list, np) {
 		if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET ||
 		    fp->f_socket == NULL)
 			continue;
@@ -615,6 +615,7 @@ sysctl_unpcblist(SYSCTLFN_ARGS)
 			error = copyout(&pcb, dp, out_size);
 			closef(fp);
 			mutex_enter(&filelist_lock);
+			np = LIST_NEXT(dfp, f_list);
 			LIST_REMOVE(dfp, f_list);
 			if (error)
 				break;

Reply via email to