On Sat, Dec 05, 2015 at 01:25:10PM -0500, Ted Unangst wrote:
> Tobias Stoeckmann wrote:
> > 
> > And I still think that the current code is a bit too permissive in parsing
> > things. I mean what's the point in allowing lines like:
> > 
> > sometextwithoutspace/bin/ksh should be used for logins # seriously!
> > 
> > Which would result in /bin/ksh, by the way.
> > 
> > Didn't notice the consequences that arise by keeping the descriptor open,
> > so I'm fine with an alternative approach. Yet we might make the code a
> > bit easier to review by not allowing such weird lines. What it should
> > expect and enforce:
> > 
> > - a valid line has to start with a slash
> > - comments are chopped off
> > - comments are supposed to be at the beginning of a line
> > 
> > So if somebody writes "/bin/ksh # comment", that actually leads to 
> > "/bin/ksh ",
> > with an additional whitespace at the end. Currently we couldn't even 
> > specify a
> > shell with a whitespace in its path.
> 
> ok. i was going to leave the behavior alone, but we can fix that too.
> 
> - use getline to read lines of any length.
> - only consider lines that start with a /.
> - truncate lines after a #, but not after spaces.
> 
> 
> Index: gen/getusershell.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/gen/getusershell.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 getusershell.c
> --- gen/getusershell.c        14 Sep 2015 16:09:13 -0000      1.16
> +++ gen/getusershell.c        5 Dec 2015 18:24:33 -0000
> @@ -28,14 +28,13 @@
>   * SUCH DAMAGE.
>   */
>  
> -#include <sys/stat.h>
> -
>  #include <ctype.h>
>  #include <limits.h>
>  #include <paths.h>
>  #include <stdint.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <string.h>
>  #include <unistd.h>
>  
>  /*
> @@ -44,7 +43,7 @@
>   */
>  
>  static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, _PATH_KSHELL, NULL };
> -static char **curshell, **shells, *strings;
> +static char **curshell, **shells;
>  static char **initshells(void);
>  
>  /*
> @@ -66,11 +65,14 @@ getusershell(void)
>  void
>  endusershell(void)
>  {
> -     
> +     char **s;
> +
> +     if ((s = shells))
> +             while (*s)
> +                     free(*s++);
>       free(shells);
>       shells = NULL;
> -     free(strings);
> -     strings = NULL;
> +
>       curshell = NULL;
>  }
>  
> @@ -84,48 +86,50 @@ setusershell(void)
>  static char **
>  initshells(void)
>  {
> -     char **sp, *cp;
> +     size_t nshells, nalloc, linesize;
> +     char *line;
>       FILE *fp;
> -     struct stat statb;
>  
>       free(shells);
>       shells = NULL;
> -     free(strings);
> -     strings = NULL;
> +
>       if ((fp = fopen(_PATH_SHELLS, "re")) == NULL)
>               return (okshells);
> -     if (fstat(fileno(fp), &statb) == -1) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     if (statb.st_size > SIZE_MAX) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     if ((strings = malloc((size_t)statb.st_size)) == NULL) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     shells = calloc((size_t)(statb.st_size / 3 + 2), sizeof (char *));
> -     if (shells == NULL) {
> -             (void)fclose(fp);
> -             free(strings);
> -             strings = NULL;
> -             return (okshells);
> -     }
> -     sp = shells;
> -     cp = strings;
> -     while (fgets(cp, PATH_MAX + 1, fp) != NULL) {
> -             while (*cp != '#' && *cp != '/' && *cp != '\0')
> -                     cp++;
> -             if (*cp == '#' || *cp == '\0')
> +
> +     line = NULL;
> +     nalloc = 10; // just an initial guess
> +     nshells = 0;
> +     shells = reallocarray(NULL, nalloc, sizeof (char *));
> +     if (shells == NULL)
> +             goto fail;
> +     linesize = 0;
> +     while (getline(&line, &linesize, fp) != -1) {
> +             if (*line != '/')
>                       continue;
> -             *sp++ = cp;
> -             while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != 
> '\0')
> -                     cp++;
> -             *cp++ = '\0';
> +             line[strcspn(line, "#\n")] = '\0';
> +             if (!(shells[nshells] = strdup(line)))
> +                     goto fail;
> +
> +             nshells++;
> +             if (nshells == nalloc) {
> +                     char **new = reallocarray(shells, nalloc * 2, 
> sizeof(char *));
> +                     if (!new)
> +                             goto fail;

This 'goto fail' will free() beyond allocated: shells[nshells--]
Better to check 'if (nshells + 1 == nalloc)' and increment nshells
afterward.

--patrick

> +                     shells = new;
> +                     nalloc *= 2;
> +             }
>       }
> -     *sp = NULL;
> +     free(line);
> +     shells[nshells] = NULL;
>       (void)fclose(fp);
>       return (shells);
> +
> +fail:
> +     free(line);
> +     while (nshells)
> +             free(shells[nshells--]);
> +     free(shells);
> +     shells = NULL;
> +     (void)fclose(fp);
> +     return (okshells);
>  }
> 

Reply via email to