Skip site navigation (1)Skip section navigation (2)
Date:      07 Mar 1997 20:10:00 -0600
From:      Zach Heilig <zach@blizzard.gaffaneys.com>
To:        "Jeffrey M. Metcalf" <jeffrey_m._metcalf@ccmail.bms.com>
Cc:        questions@freebsd.org, metcalf@snet.net
Subject:   Re: Re[2]: What does gets() unsafe question mean?
Message-ID:  <87zpwf5e2v.fsf@murkwood.gaffaneys.com>
In-Reply-To: "Jeffrey M. Metcalf"'s message of Fri, 07 Mar 1997 09:03:54 -0500 (EST)
References:  <9702078577.AA857755172@ccgate0.bms.com>

next in thread | previous in thread | raw e-mail | index | archive | help
"Jeffrey M. Metcalf" <jeffrey_m._metcalf@ccmail.bms.com> writes:

> Thank You for the reply Zach,

> I just wrote the following on a sun4

Change the program to this, and you'll see what I mean.  For some
reason, FreeBSD starts beeping after 1024 characters.  It takes 9
characters to make it core-dump on FreeBSD.  You only have to type
1 character (and enter) to see the effects.

#include <stdio.h>
#define PRINT(x) printf( #x " = %d\n", (x))
main() {
  int before = 8; /* number doesn't matter, I tried to hit an ASCII
                   * value you are unlikely to enter on a keyboard. */
  char buf[1];
  int after = 8;

  PRINT(before);
  PRINT(after);

  puts("Enter lots of text and press enter:");
  gets(buf);
  puts("\n");

  PRINT(before);
  PRINT(after);

  puts(buf);

  before=0;
  after=0;

  puts(buf);
}

That should show the problem up for sure.  It does for FreeBSD
anyway...

> Entering a huge line of text results in the _exact_ same huge line
> of text on stdout.

Hardly surprising.. You obviously did not enter enough text to
overwrite important parts of the stack.  The program modified as
above should show the problem better.  (SunOS might have different
data and return stacks?).

> Why should this be if buf was only declared to be char[1]?  Is it
> because gets is allowing me to put characters into memory
> sequentially and then when buf (pointer to the first character of
> array, buf[0]) is returned via puts, I get everything until the
> first newline?  Or does SunOS have its own implementation of
> gets()/puts()?  Incidentally, I don't get the warning message from
> SunOS.

See, the problem is gets() has no clue how big the chunk of memory
is that you passed to it.  It will happily write characters until
either the program crashes or it reads a newline.

> You mentioned gets() creates problems and security holes with
> setuid programs.  Given the result in the above paragraph from
> SunOS, is it reasonable to assume that a non setuid program that
> uses gets() on SunOS is reasonably safe if the program is well
> written?  Or is there much more involved here?

Since you the program writer won't have control over the input, it
is impossible to create a "well-written program" using gets().  Even
toy programs that write to a temporary file, and use gets() to read
it back in have a race condition (some other program can change the
file before we read it back).  You may be able to get away with
using gets() in a throwaway program, but definately do not use it
for anything serious.

> Lastly, is the fgets() function call the much better (and safer)
> choice to get a line from stream?  Since it reads 'at most n
> chars' from stream, I presume it is safer due to more controllable
> boundary conditions.  Am I correct?

Exactly, use fgets() and hack off the trailing '\n' if you don't
need/want it.  Just be careful there too, since there might not be a
trailing '\n'.  You might want to use something similar to:

char input[64], *nlptr;
while (fgets(input, sizeof input, stdin)) {
  if ((nlptr = strchr(input, '\n')))
    *nlptr = 0;
  /* do more stuff */
}

-- 
Zach Heilig (zach@blizzard.gaffaneys.com) | ALL unsolicited commercial email
Support bacteria -- it's the only         | is unwelcome.  I avoid dealing
form of culture some people have!         | with companies that email ads.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?87zpwf5e2v.fsf>