Re: gets() is dead



On Sun, 29 Apr 2007 21:06:51 +0100,
Flash Gordon <spam@xxxxxxxxxxxxxxxxxx> wrote:
In fact, if I knew how to enable such a message on my systems I *would*
enable it and remove any SW that used gets. I would especially like such
a warning enabled on the various servers I have some control over, since
I take security of servers very seriously and getting rid of
fundamentally unsafe SW is a good step towards security.

Ditto! I was only recently tempted to use library preloading and
override the standard gets() function with a function of my own, which
can be tuned to do one of the following:

1. Unconditionally convert any call to gets() to abort().

2. Unconditionally convert any call to gets() to an error message on
stderr, and a call to _exit().

3. Unconditionally convert any call to gets() to a warning message
(like the one printed by the C runtime library on FreeBSD).

4. Do nothing, but keep the 'standard' behavior of gets(), even if the
result is not optimal performance-wise.

The gets() implementation attached below seems to work for me on
FreeBSD, and I am about to test it with some larger programs on Lixux
and Solaris too in a few hours (I know this is far from a full
portability test, but it would be enough to make this modified gets()
function useful for my own work):

%%%
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define GETS_MODE_DEFAULT 0
#define GETS_MODE_WARN 1
#define GETS_MODE_EXIT 2
#define GETS_MODE_ABORT 3

char *
gets(char *buf)
{
char *options;
char *p;
int ch;
int mode;
static int warned = 0;
static char w[] =
"this program uses gets(), which is unsafe.";

mode = GETS_MODE_DEFAULT;
options = getenv("GETS_OPTIONS");
if (options != NULL) {
for (p = options; *p != '\0'; p++) {
switch (*p) {
case 'w':
case 'W':
mode = GETS_MODE_WARN;
break;
case 'e':
case 'E':
mode = GETS_MODE_EXIT;
break;
case 'a':
case 'A':
mode = GETS_MODE_ABORT;
break;
case 'd':
case 'D':
mode = GETS_MODE_DEFAULT;
break;
default:
break;
}
}
}
if (mode == GETS_MODE_ABORT) {
abort();
} else if (mode == GETS_MODE_EXIT) {
fprintf(stderr, "error: %s\n", w);
_exit(EXIT_FAILURE);
} else if (mode == GETS_MODE_WARN && warned == 0) {
fprintf(stderr, "warning: %s\n", w);
warned = 1;
}

p = buf;
while (ferror(stdin) == 0 && (ch = getchar()) != EOF && ch != '\n')
*p++ = (char)ch;
if (ferror(stdin) != 0)
return NULL;
*p = '\0';
return (buf);
}
%%%

The result so far seem to be ok, since a small test program which does
use gets() appears to fail in the expected ways when the modified gets()
is preloaded:

% $ pwd
% /home/keramida
%
% $ cat foo.c
% #include <stdio.h>
% #include <stdlib.h>
%
% int
% main(void)
% {
% char buf[100];
%
% gets(buf);
% printf("%s\n", buf);
% return EXIT_SUCCESS;
% }
%
% $ cc -fPIC -c -o gets.o gets.c
%
% $ ld -G -o libcompat.so gets.o
%
% $ echo foo bar | \
% env GETS_OPTIONS='' LD_PRELOAD=/home/keramida/libcompat.so ./a.out
% foo bar
%
% $ echo foo bar | \
% env GETS_OPTIONS='w' LD_PRELOAD=/home/keramida/libcompat.so ./a.out
% warning: this program uses gets(), which is unsafe.
% foo bar
%
% $ echo foo bar | \
% env GETS_OPTIONS='e' LD_PRELOAD=/home/keramida/libcompat.so ./a.out
% error: this program uses gets(), which is unsafe.
%
% $ echo foo bar | \
% env GETS_OPTIONS='a' LD_PRELOAD=/home/keramida/libcompat.so ./a.out
% Abort trap: 6 (core dumped)
%
% $ gdb a.out a.out.core
% [...]
% (gdb) bt
% #0 0x28151d73 in kill () at kill.S:2
% #1 0x28151d10 in __raise (s=6) at /home/build/src/lib/libc/gen/raise.c:46
% #2 0x28150a20 in abort () at /home/build/src/lib/libc/stdlib/abort.c:65
% #3 0x2807d52e in gets () from /home/keramida/libcompat.so
% #4 0x0804853e in main ()
% Current language: auto; currently asm
% (gdb)
.



Relevant Pages

  • Re: error
    ... foo.c:50: warning: string constant runs past end of line ... foo.c:7: warning: declaration of `n' shadows global declaration ... foo.c:29: warning: return type of `main' is not `int' ... char check(int n_, ...
    (comp.lang.c)
  • Re: Compile Time Error ... arghh
    ... foo.c:12: warning: function declaration isn't a prototype ... foo.c:13: warning: implicit declaration of function `malloc' ... int ccarray_destroy; ... char *dupstr; ...
    (comp.lang.c)
  • Re: please help with mysterious error....
    ... to an array of 10 char - instead of char *, which is what you get when you pass the name of an array of char to a function. ... warning: passing argument 1 of fseek discards qualifiers from pointer ... void int_fillinnumbers(int fillvalue, int startx, ... The fix here is: don't use nasty/stupid unsigned/signed-tricks! ...
    (comp.lang.c)
  • Re: somebody dropped a (warning) bomb
    ... But THE CALLER CANNOT AND MUST NOT CARE! ... Because the sign of "char" is ... warning sounds obviously insane. ... Make even "int" arguments (which ...
    (Linux-Kernel)
  • xemacs installation problems
    ... checking for gcc... ... checking whether we are using GNU C... ... checking size of int... ... configure: warning: No OffiX without generic Drag'n'Drop support ...
    (comp.os.linux.misc)