On Thu, Jun 14, 2012 at 09:48:15PM +0000, Guy Helmer wrote:
> Author: ghelmer
> Date: Thu Jun 14 21:48:14 2012
> New Revision: 237106
> URL: http://svn.freebsd.org/changeset/base/237106
> 
> Log:
>   MFC 235739-235740,236402:
>   Apply style(9) to return and switch/case statements.
>   
>   Add checks for memory allocation failures in appropriate places, and
>   avoid creating bad entries in the grp list as a result of memory allocation
>   failures while building new entries.
>   
>   Style(9) improvements: remove unnecessary parenthesis, improve order
>   of local variable declarations, remove bogus casts, and resolve long
>   lines.
>   
>   PR:         bin/83340
> 
> Modified:
>   stable/9/lib/libc/gen/getnetgrent.c
> Directory Properties:
>   stable/9/lib/libc/   (props changed)
> 
This broke mountd(8) for me. It dies with SIGSEGV on start. Autopsy has
shown that this happen due to free(3) on an unallocated pointer.

I have two netgroups in my /etc/netgroup:
testboxes (solo.home, , ) (x.home, , ) (nv.home, , ) (sandy.home, , ) 
(tom.home, ,)
laptops (alf.home, , ) (alf.home-air, , ) (sirion.home, , ) (sirion.home-air, , 
)

The http://people.freebsd.org/~kib/misc/netgr.c shows the issue. Run it
as "netgr testboxes laptops".

Your change below makes lp->l_lines pointer for already processed groups
invalid because you reallocf(3) the memory pointed by it. Then
1. accessing the l_lines later causes undefined behaviour;
2. free(3) call in endnetgrent() dies because pointer is dandling.

> @@ -595,15 +615,15 @@ read_for_group(const char *group)
>                               } else
>                                       cont = 0;
>                               if (len > 0) {
> -                                     linep = (char *)malloc(olen + len + 1);
> -                                     if (olen > 0) {
> -                                             bcopy(olinep, linep, olen);
> -                                             free(olinep);
> +                                     linep = reallocf(linep, olen + len + 1);
> +                                     if (linep == NULL) {
> +                                             free(lp->l_groupname);
> +                                             free(lp);
> +                                             return (NULL);
>                                       }
>                                       bcopy(pos, linep + olen, len);
>                                       olen += len;
>                                       *(linep + olen) = '\0';
> -                                     olinep = linep;
>                               }
>                               if (cont) {
>                                       if (fgets(line, LINSIZ, netf)) {

Below is partial revert of your changes that cures mountd for me. Also,
the second patch does some further cleanup of the getnetgrent.c.

Do you agree ?

commit d5cb6720e8d12b281e89f2487561fe95addd0e34
Author: Konstantin Belousov <k...@freebsd.org>
Date:   Sat Jun 16 00:21:11 2012 +0300

    Partially revert r235740, namely, allocate separate blocks of memory
    for each group' l_line. Using the reallocf(3) invalidates l_line's of
    the previously read groups.

diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c
index 933a7d3..8cad6c4 100644
--- a/lib/libc/gen/getnetgrent.c
+++ b/lib/libc/gen/getnetgrent.c
@@ -538,7 +538,7 @@ parse_netgrp(const char *group)
 static struct linelist *
 read_for_group(const char *group)
 {
-       char *pos, *spos, *linep;
+       char *pos, *spos, *linep, *olinep;
        int len, olen;
        int cont;
        struct linelist *lp;
@@ -615,15 +615,20 @@ read_for_group(const char *group)
                                } else
                                        cont = 0;
                                if (len > 0) {
-                                       linep = reallocf(linep, olen + len + 1);
+                                       linep = malloc(olen + len + 1);
                                        if (linep == NULL) {
                                                free(lp->l_groupname);
                                                free(lp);
                                                return (NULL);
                                        }
+                                       if (olen > 0) {
+                                               bcopy(olinep, linep, olen);
+                                               free(olinep);
+                                       }
                                        bcopy(pos, linep + olen, len);
                                        olen += len;
                                        *(linep + olen) = '\0';
+                                       olinep = linep;
                                }
                                if (cont) {
                                        if (fgets(line, LINSIZ, netf)) {


commit 5946753b4b094d5f7ac41792df64915434567fd8
Author: Konstantin Belousov <k...@freebsd.org>
Date:   Sat Jun 16 00:23:01 2012 +0300

    More style.

diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c
index 8cad6c4..d94fff7 100644
--- a/lib/libc/gen/getnetgrent.c
+++ b/lib/libc/gen/getnetgrent.c
@@ -161,8 +161,7 @@ setnetgrent(const char *group)
        if (group == NULL || !strlen(group))
                return;
 
-       if (grouphead.gr == (struct netgrp *)0 ||
-               strcmp(group, grouphead.grname)) {
+       if (grouphead.gr == NULL || strcmp(group, grouphead.grname)) {
                endnetgrent();
 #ifdef YP
                /* Presumed guilty until proven innocent. */
@@ -172,7 +171,7 @@ setnetgrent(const char *group)
                 * use NIS exclusively.
                 */
                if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
-                       errno == ENOENT) || _yp_statp.st_size == 0)
+                   errno == ENOENT) || _yp_statp.st_size == 0)
                        _use_only_yp = _netgr_yp_enabled = 1;
                if ((netf = fopen(_PATH_NETGROUP,"r")) != NULL ||_use_only_yp){
                /*
@@ -247,27 +246,24 @@ endnetgrent(void)
                lp = lp->l_next;
                free(olp->l_groupname);
                free(olp->l_line);
-               free((char *)olp);
+               free(olp);
        }
-       linehead = (struct linelist *)0;
+       linehead = NULL;
        if (grouphead.grname) {
                free(grouphead.grname);
-               grouphead.grname = (char *)0;
+               grouphead.grname = NULL;
        }
        gp = grouphead.gr;
        while (gp) {
                ogp = gp;
                gp = gp->ng_next;
-               if (ogp->ng_str[NG_HOST])
-                       free(ogp->ng_str[NG_HOST]);
-               if (ogp->ng_str[NG_USER])
-                       free(ogp->ng_str[NG_USER]);
-               if (ogp->ng_str[NG_DOM])
-                       free(ogp->ng_str[NG_DOM]);
-               free((char *)ogp);
+               free(ogp->ng_str[NG_HOST]);
+               free(ogp->ng_str[NG_USER]);
+               free(ogp->ng_str[NG_DOM]);
+               free(ogp);
        }
-       grouphead.gr = (struct netgrp *)0;
-       nextgrp = (struct netgrp *)0;
+       grouphead.gr = NULL;
+       nextgrp = NULL;
 #ifdef YP
        _netgr_yp_enabled = 0;
 #endif
@@ -282,7 +278,7 @@ _listmatch(const char *list, const char *group, int len)
        int glen = strlen(group);
 
        /* skip possible leading whitespace */
-       while(isspace((unsigned char)*ptr))
+       while (isspace((unsigned char)*ptr))
                ptr++;
 
        while (ptr < list + len) {
@@ -291,7 +287,7 @@ _listmatch(const char *list, const char *group, int len)
                        ptr++;
                if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
                        return (1);
-               while(*ptr == ','  || isspace((unsigned char)*ptr))
+               while (*ptr == ','  || isspace((unsigned char)*ptr))
                        ptr++;
        }
 
@@ -436,8 +432,7 @@ parse_netgrp(const char *group)
                        break;
                lp = lp->l_next;
        }
-       if (lp == (struct linelist *)0 &&
-           (lp = read_for_group(group)) == (struct linelist *)0)
+       if (lp == NULL && (lp = read_for_group(group)) == NULL)
                return (1);
        if (lp->l_parsed) {
 #ifdef DEBUG

Attachment: pgpEQvo8EQIaP.pgp
Description: PGP signature

Reply via email to