[patch] Fix BZ #18660 -- overflow in getusershell

Mike Frysinger vapier@gentoo.org
Wed Aug 19 18:28:00 GMT 2015


On 19 Aug 2015 09:28, Paul Pluzhnikov wrote:
> On Wed, Aug 19, 2015 at 7:55 AM, Mike Frysinger wrote:
> > /* These functions are not thread safe (by design), so globals are OK.  */
> > static FILE *shellfp;
> > static int okshell_idx;
> > static char *shellbuf;
> > static size_t buf_len;
> >
> > char *
> > getusershell (void)
> > {
> >   /* Handle the builtin case first.
> >
> >      NB: we do not use a global array here as the initialization needs
> >      relocations.  These interfaces are used so rarely that this is not
> >      justified.  Instead open code it with a switch statement.  */
> >   switch (okshell_idx)
> >     {
> >     case 0:
> >       /* Require the user call setusershell first.  */
> >       assert (shellfp != NULL);
> 
> I could find no man page that requires user calling setusershell first.
> Is there a definitive description of this interface?

hmm, looks like freebsd, openbsd, darwin, and gnulib don't require this.
i'll drop that.

> >   while (getline (&shellbuf, &buf_len, shellfp) != -1)
> >     {
> >       char *p;
> >
> >       /* Strip out any comment lines.  */
> >       p = strchr (shellbuf, '#');
> >       if (p)
> >         *p = '\0';
> >       else
> >         {
> >           /* Chop the trailing newline.  */
> >           p = strchr (shellbuf, '\n');
> 
> Current version chops on white space. Do we want to return "/foo bar"
> here? Of course any sysadmin who puts "/foo bar" into /etc/shells gets
> what he deserves.

the old logic is even worse than that.  it skips all leading bytes until it
finds a slash and then returns things after that, while splitting on space.
so a line like:
	space/foobar cow
will return "/foobar".

the docs i've seen (darwin, freebsd, linux) leave it fairly vague and say
"valid user shell".  but no one validates things, and really only document
comments and blank lines.  i think we should just go with that.

> >       /* Only accept valid shells (which we define as starting with a '/').  */
> >       if (shellbuf[0] == '/')
> 
> Do we want to return "/" as a valid shell here?

the current already does :).  since we aren't checking the path in the file 
(i.e. running stat and seeing if it's a +x file), i don't think we want to
treat / specially.  afterall, "/bogus" or "/bin" or "/sbin/" will still get
returned.

> > void
> > setusershell (void)
> > {
> >   /* We could rewind shellfp here, but we get smaller code this way.
> >      Keep in mind this is not a performance sensitive API.  */
> >   endusershell ();
> >
> >   shellfp = fopen (_LOCAL_PATH_SHELLS, "rce");
> >   if (shellfp == NULL)
> >     okshell_idx = 1;
> 
> I think you missed a part here:
> 
>   else
>     okshell_idx = 4;

nope ... current code is correct.  see how the value of 0 is treated (which is 
also the default since it's a bss var).
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: getusershell.c
Type: text/x-c
Size: 2847 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20150819/2956d44a/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20150819/2956d44a/attachment.sig>


More information about the Libc-alpha mailing list