[1557] in linux-security and linux-alert archive

home help back first fref pref prev next nref lref last post

[linux-security] an anti-overflow wrapper

daemon@ATHENA.MIT.EDU (Thomas Roessler)
Tue May 27 05:51:22 1997

Date: Mon, 26 May 1997 19:53:51 +0200
From: Thomas Roessler <roessler@guug.de>
To: linux-security@redhat.com
Resent-From: linux-security@redhat.com
Reply-To: linux-security@redhat.com

The following code is a first attempt at a simple but flexible
suid wrapper which checks argv[] and environment.  It might
introduce new security holes or have other bugs; using 1 as a
general failure exit value may be the wrong thing to do.  The
wrapper reads a configuration file named /etc/wrapper.cfg; see
the comments in wrapper.c for the file's format.

Flame, comment, or use at will.

tlr
------------------------------ wrapper.c ------------------------------
/*
 * wrapper.c (c) 1997 Thomas Roessler <roessler@guug.de>
 * $Id: wrapper.c,v 1.2 1997/05/26 17:39:09 roessler Exp $
 *
 * This program is free software. You may use, modify or distribute it
 * at will as long as you give credit to the original author.
 *
 * format of /etc/wrapper.cfg:
 * - leading white space is ignored.
 * - lines starting with a hash sign (#) are ignored.
 * - empty lines are ignored.
 * 
 * Each line consists of three whitespace-separated fields:
 * <program> <what> <size>
 *
 * <program> is the real path name as compiled into the wrapper as REALPROG,
 * <what> can either be the string "argv", a $ sign followed  by the name
 * of an environment variable or a $ sign followed by an asterisk
 * to match all environment variables passed to the program.
 *
 * Sample:
 *
 * /usr/X11R6/bin/xterm	argv 1024
 * /usr/X11R6/bin/xterm $HOME 1024
 * /usr/X11R6/bin/xterm $* 2048
 *
 * To wrap, e.g., xterm, move /usr/X11R6/bin/xterm to 
 * /usr/X11R6/bin/xterm.wrapped, compile this wrapper by typing
 * cc -DREALPROG=\"/usr/X11R6/bin/xterm\" wrapper.c -o xterm,
 * and move it to /usr/X11R6/bin/xterm. Don't forget to remove
 * the suid bits from the wrapped program and to add them to the 
 * wrapper!
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <syslog.h>
#include <unistd.h>

#define BUFFSIZE 1024
#define CFGFILE "/etc/wrapper.cfg"

extern char **environ;

void syntax(const char *s)
{
  syslog(LOG_ERR, "WRAPPER: error in %s: %s.", CFGFILE, s);
  fprintf(stderr, "Syntax error in %s. Please notify the system\n"
	  "administration.\n", CFGFILE);
}

int main(int argc, char *argv[])
{
  FILE *cfgfile;
  char buff[BUFFSIZE];
  char *f = NULL;
  char *s;
  char *t;
  char *u;
  char *key;
  char *value;
  char **e;
  size_t len;
  int i;
  

  openlog(argv[0], 0, LOG_AUTHPRIV);

  if(!(cfgfile = fopen(CFGFILE, "r"))) {
    syslog(LOG_ERR, "WRAPPER: Can't open %s: %m.", CFGFILE);
    exit(1);
  }

  while(fgets(buff, sizeof(buff), cfgfile)) {
    if(!(s = strchr(buff, '\n'))) {
      syntax("Long line.");
      exit(1);
    }
    
    *s = '\0';

    /* ignore leading whitespace */

    for(s = buff; *s && isspace(*s); s++)
      ;

    if(*s == '\0' || *s == '#')
      continue;

    if(!(s = strtok(s, " \t"))) {
      syntax("Syntax error.");
      exit(1);
    }

    if(!strcmp(s, REALPROG)) {
      if(!(s = strtok(NULL, " \t")) || !(t = strtok(NULL, " \t"))) {
	syntax("Syntax error.");
	exit(1);
      }
      
      len = strtoul(t, NULL, 0);
      if(!len) {
	syntax("Bad number.");
	exit(1);
      }
      
      if(*s == '$') { /* environment variable */
	s++;

	for(e = environ; *e; e++) {
	  if((f = strdup(*e)) == NULL) {
	    syslog(LOG_ERR, "WRAPPER: Out of memory. %m.");
	    fprintf(stderr, "Out of memory.\n");
	    exit(1);
	  }

	  if(!(u = strchr(f, '='))) {
	    syslog(LOG_ALERT, "WRAPPER: Insane environment entry: %s.",
		   f);
	    exit(1);
	  }

	  key = f;
	  *u++ = '\0';
	  value = u;
	  
	  if((*s == '*' || !strcmp(s, key)) && strlen(value) > len) {
	    syslog(LOG_ALERT, "WRAPPER: $%s is too long.",
		   key);
	    exit(1);
	  }
	  
	  free(f);
	}
      } else if(!strcasecmp(s, "argv")) { /* argument vector */
	
	for(i = 0; i < argc; i++) {
	  if(strlen(argv[i]) > len) {
	    syslog(LOG_ALERT, "WRAPPER: Security violation: argument too long."
		   "(uid = %d, euid = %d)",
		   (int) getuid(), (int) geteuid());
	    exit(1);
	  }
	}
      } else { /* syntax error */
	syntax("Unknown check.");
	exit(1);
      }
    }
  }

  fclose(cfgfile);
  closelog();

  execv(REALPROG ".wrapped", argv);
  
  syslog(LOG_ERR, "WRAPPER: can't exec %s: %m.",
	 REALPROG ".wrapped");
  exit(1);
}
------------------------------ Makefile ------------------------------
SUID_PROGS=/usr/X11R6/bin/xterm
CFLAGS=-Wall -Wstrict-prototypes -pedantic

all: $(SUID_PROGS)

clean:
	rm -f *~ *.o
	for i in $(SUID_PROGS) ; do rm -f `basename $$i` ; done

$(SUID_PROGS): wrapper.c
	$(CC) $(CFLAGS) -DREALPROG=\"$@\" -o `basename $@` $^
------------------------------ The End ------------------------------


home help back first fref pref prev next nref lref last post