Commit 30e328cbf14d03fc9f6569e93e0dac41526264d8

Guillem Jover 2014-11-03T00:43:27

Do not close file descriptors while scanning the /proc filesystem Closing file descriptors changes the content of the fd directories in the /proc filesystem, which means readdir() might get very confused. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85663

diff --git a/src/closefrom.c b/src/closefrom.c
index 27aa26f..b6d9834 100644
--- a/src/closefrom.c
+++ b/src/closefrom.c
@@ -129,6 +129,10 @@ closefrom_procfs(int lowfd)
 	const char *path;
 	DIR *dirp;
 	struct dirent *dent;
+	int *fd_array = NULL;
+	int fd_array_used = 0;
+	int fd_array_size = 0;
+	int i;
 
 	/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
 # if defined(__FreeBSD__) || defined(__APPLE__)
@@ -145,10 +149,30 @@ closefrom_procfs(int lowfd)
 		int fd;
 
 		fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
-		if (errstr == NULL && fd != dirfd(dirp))
-			closefrom_close(fd);
+		if (errstr != NULL || fd == dirfd(dirp))
+			continue;
+
+		if (fd_array_used >= fd_array_size) {
+			int *ptr;
+
+			if (fd_array_size > 0)
+				fd_array_size *= 2;
+			else
+				fd_array_size = 32;
+
+			ptr = reallocarray(fd_array, fd_array_size, sizeof(int));
+			if (ptr == NULL)
+				break;
+			fd_array = ptr;
+		}
+
+		fd_array[fd_array_used++] = fd;
 	}
 
+	for (i = 0; i < fd_array_used; i++)
+		closefrom_close(fd_array[i]);
+
+	free(fd_array);
 	(void)closedir(dirp);
 
 	return 0;