Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 08 Apr 1999 17:17:35 -0400
From:      Mark S Feldman <feldman@tislabs.com>
To:        freebsd-security@freebsd.org
Cc:        feldman@tislabs.com
Subject:   Generic Software Wrappers
Message-ID:  <199904082117.RAA13119@clipper.gw.tislabs.com>

next in thread | raw e-mail | index | archive | help

Almost 8 months back, I responded to a message on this list and
described a research project we were working on.  My message is below.
At the end of the message, I said I would send another message to this
list when we made our source available.  Well, the first release of
our Generic Software Wrappers Tool Kit -- still very much a research
prototype -- is available.  It runs under FreeBSD 2.2.x, Solaris 2.6,
and, as much as we have ported to date, under Windows NT 4.0.  We're
limited to FreeBSD 2.2.x because we don't currently have the resources
to port to 3.x.  Check out ftp://ftp.tislabs.com/pub/wrappers if
you're interested.

  Mark


------- Forwarded Message

To: Philippe Regnauld <regnauld@deepo.prosa.dk>
cc: freebsd-security@freebsd.org, badger@tis.com, feldman@tis.com,
        Robert Watson <robert@cyrus.watson.org>
Subject: Re: Fwd: "Using capabilties aaginst shell code" <dps@IO.STARGATE.CO.UK> (fwd) 
Date: Wed, 19 Aug 1998 11:14:17 -0400
From: Mark S Feldman <feldman@tis.com>
Sender: owner-freebsd-security@freebsd.org
X-Loop: FreeBSD.org
Content-Type: text
Content-Length: 7470


Philippe, 

Your message to the freebsd-security list was passed to me.  I'm the
project leader for the Generic Software Wrappers project at TIS Labs
at Network Associates.  In short, under DARPA contract
F30602-96-C-0333, we have developed a Wrapper Definition Language
(WDL) based on 'C' which makes it easy to identify system events of
interest (e.g., named system calls, all system calls containing a path
parameter, system calls available only to root), to intercept them,
and to deny, augment, or transform those events.

We have developed a prototype under FreeBSD, including a wrapper
compiler which compiles WDL into 'C', a Wrapper Support Subsystem
implemented as a Loadable Kernel Module, and various support programs.
We are currently porting to Solaris and Windows NT.  Our source is not
currently organized for distribution, but, once it is, it will be made
available for free for non-commercial use.

> 	Is this any form of restriction that can be implemented 
> 	in *BSD systems ?  I.e.: restricting system calls to
> 	certain classes of daemons ?

One of our simpler wrappers is the noadmin wrapper, which prevents a
wrapped process, even one running as root, from executing certain
administrative system calls::

 /* 
  * $Id: noadmin.wr,v 1.5 1998/04/20 19:05:08 ko Exp $
  *
  * noadmin.wr
  *
  * A wrapper that denies certain administrative syscalls.
  */

 #include "../../wr.include/bsd.ch"

 wrapper noadmin {
    bsd::op{mount || unmount || ptrace || quotactl || acct || swapon || 
	    mknod || adjtime || ktrace || reboot || settimeofday} pre { 
       return WR_DENY | WR_BADPERM;
    };
 }

In the wrapper, bsd.ch contains a characterization of the system API.
It starts with the 'C' prototype, and then adds additional attributes
that make it possible to group system calls and to deal with their
parameters.  The wrapper runs in the bsd domain and looks for the
named operations.  It intercepts before the operation occurs (pre
keyword), prevents it from executing, making it appear to be a
permission denied-type error.

> 	As mentioned in the example below, why should POPd be allowed
> 	to exec() ?  This seems like a very sane approach (of course,
> 	it implies knowledge/auditing of the code).

In addition to our wrappers, which specify what events to look for and
how to handle them, we have activation criteria, which determine which
wrappers wrap a process.  Activation criteria are simple boolean
expressions which can be based on the uid, gid, program name, etc.  If
the pop daemon were named popd, the following activation criteria
would cause it to be wrapped by the noadmin wrapper:

  prog == popd ==> noadmin

As for not knowing what system calls a process needs to get the job
done, it could first be run under a wrapper like dbcallcount, which
tracks all system calls made by wrapped processes and uses Wrapper
Query Language (WQL) to store call counts in our fast, lightweight
database which can be viewed using our GUI or CLI from user space:

 /* 
  * $Id: dbcallcount.wr,v 1.7 1998/08/06 19:45:17 ko Exp $
  *
  * dbcallcount.wr
  * 
  * This wrapper keeps track of the number of times each syscall is
  * attempted.
  *
  * Use the "wrselect" program to view the tables created.
  *
  */

 #include "../../wr.include/bsd.ch"
 #include "../../wr.include/libwr.h"

 wrapper dbcallcount {

     DBTABLE callcountTable {
	 char(20) key name;
	 int count;
     };

     callcountTable callcount;

     wr_activate() {
	 int i;
	 /* create the table. */
	 i = wql {
	     create table callcount;
	 };
	 if (i < 0)
	     wr_printf("Error creating table.\n");
     }

     wr_duplicate() {
	 /* create the table. */
	 wql {
	     create table callcount;
	 };
     }

     wr_deactivate() {
	 /* Drop the table. */
	 wql {
	     drop table callcount;
	 };
     }

     /* Catch all syscalls */

     bsd::op{*} pre { 
	 int retVal;

	 /* If syscall in in the db, increment count. */
	 /* If not, add the syscall to the database. */ 

	 retVal = wql {
		 update callcount
		     set .count = .count + 1
		     where
			 .name = $$;
	 };

	 if (retVal <= 0) {
	     wql {
		 insert into callcount values
		     ($$, 1);
	     };
	 }
    };
 }

> 
> 	Then we could have certain untrusted (i.e.: running as
> 	root) daemons launched in such an environment, on top
> 	of being chroot()ed.
...

Yup.  And wrappers provide a mechanism to do that.  Take a look at the
following wrapper which creates a simple, if silly, synthetic
environment:

 /*
  * $Id: dbsynthetic.wr,v 1.5 1998/08/19 15:30:08 feldman Exp $
  *
  * This wrapper provides a synthetic environment, doing string
  * substitutions on path names.
  *
  */

 #include "../../wr.include/bsd.ch"
 #include "../../wr.include/libwr.h"

 wrapper dbsynthetic {

   /* Null-terminated array of substition string pairs.  Each target
    * entry, if found in a path, will be replaced by the replacement
    * entry. Regular expressions, as defined in WDL, can be used for
    * the targets. */

     DBTABLE path_table {
	  char(256)		target;
	  char(256)		replacement;
     };

     DBTABLE alert_table {
	  char(256)               path;
	  char(256)               fullname;
	  int                     pid;
	  int                     uid;
     };

     path_table global pathnames;
     alert_table global alerts;

     wr_install() {
	  DBROW::path_table row;
	  wql {
	      create table pathnames;
	      create table alerts;

	      insert into pathnames values
		      ( "/etc/master.passwd",    "/etc/passwd"),
		      ( "/kernel",               "/etc/motd"),
		      ( "/lkm",                  "/tmp"),
		      ( "/usr/games",            "/usr/bin"),
		      ( "/usr/tmp",              "/tmp"),
		      ( "/var/tmp",              "/tmp") ;

	      select into row from pathnames;
	  };
     }

     wr_uninstall() {
	  wql {
	      drop table pathnames;
	      drop table alerts;
	  };
     }

     /* Intercept all syscalls containing paths before they run */

     bsd::pattr{path} pre {
	  DBROW::path_table row;
	  string fullname;
	  int changed = 0;

	  /* Attempt to convert path from relative to absolute.  If
	   * the conversion doesn't succeed, it's a bad path.  This
	   * would normally be the end, but since we may be
	   * redirecting from a non-existent path to one that exists,
	   * we'll proceed */

	  if ((fullname = wr_abspath($path)) == NULL) {
	      fullname = wr_strdup($path);
	  }

	  wql {
	      select into row from pathnames;
	  };

	  do {
	      /* Do string substitutions for each pair of pathnames 
	       * and remember if any occurred. */

	      if (fullname =~ s|row.target|row.replacement|)
		  changed++;
	  } while (row.next());

	  /* Write out an alert to the database and change the path
	   * parameter if any substitutions occurred. */

	  if (changed) {
	      wql {
		  insert into alerts values ($path, fullname, _pid, _uid);
	      };
	      $path = fullname;
	  }

	  /* Cleanup */

	  wr_free(fullname);
     };
 }

My response is undoubtedly way too long.  I'll make sure that a
message is sent to this list when we make our source available.  In
the mean time, if you have any questions, let me know.

  Mark
 
- -----
Mark S. Feldman
TIS Labs at Network Associates, Inc.             phone: +1 301 854 6889
3060 Washington Road                             fax:   +1 301 854 5363
Glenwood, Maryland 21738


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe security" in the body of the message

------- End of Forwarded Message



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message




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