From nobody@FreeBSD.org  Sat Jul 31 15:06:17 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id EFE0A1065673
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Jul 2010 15:06:16 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id DFF918FC17
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Jul 2010 15:06:16 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o6VF6GdM000770
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 31 Jul 2010 15:06:16 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o6VF6G0J000769;
	Sat, 31 Jul 2010 15:06:16 GMT
	(envelope-from nobody)
Message-Id: <201007311506.o6VF6G0J000769@www.freebsd.org>
Date: Sat, 31 Jul 2010 15:06:16 GMT
From: pluknet <pluknet@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [patch] BSD grep loops with EISDIR trying to read a directory
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         149152
>Category:       bin
>Synopsis:       [patch] grep(1): BSD grep loops with EISDIR trying to read a directory
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    gabor
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jul 31 15:10:04 UTC 2010
>Closed-Date:    
>Last-Modified:  Sat Jul 31 20:16:57 UTC 2010
>Originator:     pluknet
>Release:        HEAD r210642
>Organization:
>Environment:
FreeBSD foo 9.0-CURRENT FreeBSD 9.0-CURRENT #36: Fri Jul 23 10:30:36 UTC 2010     root@foo:/usr/obj/usr/src/sys/GENERIC amd64

>Description:
BSD grep used in -CURRENT loops when it gets a directory
as a file argument for grepping.

grep open()'s a dir, stat()'s that dir, and do a read() on that dir
in an endless loop. It seems that grep has no enough error handling.
>How-To-Repeat:
Loop easily reproducible. Try this (on -CURRENT sources):
grep IP_FW_GET /sys/netinet/ipfw*; or
grep IP_FW_GET /sys/netinet/ip*; or
grep IP_FW_GET /sys/netinet/*

That will produce something like this:
[...]
 41740 grep     CALL  stat(0x7fffffffe6d4,0x7fffffffda50)
 41740 grep     NAMI  "/sys/netinet/ipfw"
 41740 grep     STRU  struct stat {dev=67174149, ino=47296976,
mode=drwxr-xr-x , nlink=4, uid=0, gid=0, rdev=94607662,
atime=1276302257, stime=1279007706, ctime=1279007706, birthtime=-1,
size=1024, blksize=4096, blocks=4, flags=0x0 }
 41740 grep     RET   stat 0
 41740 grep     CALL  open(0x7fffffffe6d4,O_RDONLY,<unused>0x1b6)
 41740 grep     NAMI  "/sys/netinet/ipfw"
 41740 grep     RET   open 3
 41740 grep     CALL  stat(0x507300,0x7fffffffd860)
 41740 grep     NAMI  "/sys/netinet/ipfw"
 41740 grep     STRU  struct stat {dev=67174149, ino=47296976,
mode=drwxr-xr-x , nlink=4, uid=0, gid=0, rdev=94607662,
atime=1276302257, stime=1279007706, ctime=1279007706, birthtime=-1,
size=1024, blksize=4096, blocks=4, flags=0x0 }
 41740 grep     RET   stat 0
 41740 grep     CALL  fstat(0x3,0x7fffffffd730)
 41740 grep     STRU  struct stat {dev=67174149, ino=47296976,
mode=drwxr-xr-x , nlink=4, uid=0, gid=0, rdev=94607662,
atime=1276302257, stime=1279007706, ctime=1279007706, birthtime=-1,
size=1024, blksize=4096, blocks=4, flags=0x0 }
 41740 grep     RET   fstat 0
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
 41740 grep     RET   read -1 errno 21 Is a directory
 41740 grep     CALL  read(0x3,0x800c38000,0x1000)
[...]
>Fix:
This is a sort of concept to demonstrate a possible way
to handle around the issue.

Patch attached with submission follows:

Index: file.c
===================================================================
--- file.c	(revision 210642)
+++ file.c	(working copy)
@@ -164,9 +164,12 @@
 			lnbuflen *= 2;
 			lnbuf = grep_realloc(lnbuf, ++lnbuflen);
 		}
-		if ((ch == '\n') || (ch == EOF)) {
+		if ((ch == '\n') || (ch == EOF && errno != EISDIR)) {
 			lnbuf[i] = '\0';
 			break;
+		} else if (ch == EOF && errno == EISDIR) {
+			lnbuf[i] = '\0';
+			return (NULL); /* XXX unclear why '\0' doesn't work */
 		} else
 			lnbuf[i] = ch;
 	}


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->gabor 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sat Jul 31 20:16:41 UTC 2010 
Responsible-Changed-Why:  
Over to maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=149152 
>Unformatted:
