misc/109206: setgroups with incomplete list if line exceeds 1kB

Gerd Rausch gerd at juniper.net
Thu Feb 15 19:10:06 UTC 2007


>Number:         109206
>Category:       misc
>Synopsis:       setgroups with incomplete list if line exceeds 1kB
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 15 19:10:05 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Gerd Rausch
>Release:        6.1
>Organization:
Juniper Networks
>Environment:
>Description:
This is a bug in libc not handling group lines that exceed 1kB in size
correctly.

The group parsing functions start with a 1k buffer and increase it if
there is need for more space in order to accommodate a line.

Unfortunately, they do not reposition the file pointer so that when
trying to read the line again with an increased buffer size , the
groups that were supposed to be inclueded for a user did not get
picked up.

Fix is to re-position the stream if a situation occurs that we need
more space (i.e. errno == ERANGE).

>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: lib/libc/gen/getgrent.c
===================================================================
RCS file: /cvs/junos-2001/src/lib/libc/gen/getgrent.c,v
retrieving revision 1.3.68.2
diff -u -p -r1.3.68.2 getgrent.c
--- lib/libc/gen/getgrent.c	24 Jun 2006 02:58:49 -0000	1.3.68.2
+++ lib/libc/gen/getgrent.c	14 Feb 2007 23:55:31 -0000
@@ -446,6 +446,8 @@ files_group(void *retval, void *mdata, v
 	char			*buffer;
 	size_t			 bufsize, linesize;
 	int			 rv, stayopen, *errnop;
+	fpos_t			 saved_pos;
+	int			 have_saved_pos;
 
 	name = NULL;
 	gid = (gid_t)-1;
@@ -481,7 +483,10 @@ files_group(void *retval, void *mdata, v
 		stayopen = st->stayopen;
 	}
 	rv = NS_NOTFOUND;
-	while ((line = fgetln(st->fp, &linesize)) != NULL) {
+	while (1) {
+		have_saved_pos = fgetpos(st->fp, &saved_pos) == 0;
+		if ((line = fgetln(st->fp, &linesize)) == NULL)
+			break;
 		if (line[linesize-1] == '\n')
 			linesize--;
 		rv = __gr_match_entry(line, linesize, how, name, gid);
@@ -503,6 +508,12 @@ files_group(void *retval, void *mdata, v
 		if (rv & NS_TERMINATE)
 			break;
 	}
+	if (rv == NS_RETURN && *errnop == ERANGE) {
+		if (!have_saved_pos || fsetpos(st->fp, &saved_pos) != 0) {
+			*errnop = ESPIPE;
+			rv = NS_UNAVAIL;
+		}
+	}
 	if (!stayopen && st->fp != NULL) {
 		fclose(st->fp);
 		st->fp = NULL;
@@ -908,6 +919,8 @@ compat_group(void *retval, void *mdata, 
 	void			*discard;
 	size_t			 bufsize, linesize;
 	int			 rv, stayopen, *errnop;
+	fpos_t			 saved_pos;
+	int			 have_saved_pos;
 
 #define set_lookup_type(x, y) do { 				\
 	int i;							\
@@ -1010,7 +1023,10 @@ docompat:
 		break;
 	}
 	rv = NS_NOTFOUND;
-	while ((line = fgetln(st->fp, &linesize)) != NULL) {
+	while (1) {
+		have_saved_pos = fgetpos(st->fp, &saved_pos) == 0;
+		if ((line = fgetln(st->fp, &linesize)) == NULL)
+			break;
 		if (line[linesize-1] == '\n')
 			linesize--;
 		if (linesize > 2 && line[0] == '+') {
@@ -1051,6 +1067,12 @@ docompat:
 		if (rv & NS_TERMINATE)
 			break;
 	}
+	if (rv == NS_RETURN && *errnop == ERANGE) {
+		if (!have_saved_pos || fsetpos(st->fp, &saved_pos) != 0) {
+			*errnop = ESPIPE;
+			rv = NS_UNAVAIL;
+		}
+	}
 fin:
 	if (!stayopen && st->fp != NULL) {
 		fclose(st->fp);

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list