From: buzz@toxicavenger.bear.com (Buzz Moschetti)
Newsgroups: comp.security.misc
Subject: Re: Secure setuid mount program: A model!
Date: 19 Aug 92 20:36:01 GMT
Reply-To: buzz@fsrg.bear.com
Distribution: comp
Organization: Bear, Stearns & Co. Inc.
In-reply-to: buzz@toxicavenger.bear.com's message of 19 Aug 92 13:26:22 GMT

In article <BUZZ.92Aug19092622@toxicavenger.bear.com> buzz@toxicavenger.bear.com (Buzz Moschetti) writes:

   I believe this (mmount) to be secure.  Can someone claim otherwise?

I should have more fully qualified who and what the "non-root" users were
doing.  They happen to be operators who know the root password anyway.  We just
want to provide them with a facility that they can use with their regular IDs
in order to avoid having to become root.

In any case, the objective is to see if someone other than the trusted users
can (ab)use the mmount facility to acquire a root privilege command interface
of some sort.

The program need only insulate itself from surreptitious undermining; once the
user has been *authenticated*, then *authorization* and capabilities -- such
as mounting setuid floppy media, overmounting existing mounts, umounting
critical filesystems, etc. -- is another matter that can be controlled from
inside the program.

Here, then, is a simple version of mmount.c:

---8<------8<------8<------8<------8<------8<------8<------8<------8<---

/*
Here is a "model" safe setuid program -- thanks to all who sent
me mail with suggestions.  Features include:

1.  All sigs except SIGKILL and SIGCHLD shut down.
2.  All file descriptors except for stdin, out, & err closed prior to exec.
3.  "Trusted environment" only is passed via exeve().
4.  Static linking to be EXTRA safe; eliminates the dynamic load issue.

Edit the obvious things (trusted_user, etc.) and compile this program with:
cc mmount.c -Bstatic -o mmount

The binary should be stripped and chmod-ed to 4711 to prevent strings(1)
from being run on it.  It works just fine on SunOS 4.1.1 using the plain
ol' /bin/cc C compiler.  I left in some debugging printf()s; these would
be eliminated in a "production" version.

Can anyone add anything else?  Are we secure yet?
*/

#include <stdio.h>
#include <signal.h>

#include <pwd.h>
#include <sys/wait.h>



static char *trusted_user = "buzz";

static char *trusted_env[] = {
      "PATH=/usr/etc",
      0
};

main(argc, argv)
int argc;
char **argv;
{
      struct passwd *uid_ent;
      int uid, euid;
      int pid, i;
      int status;
      char **p;

      /*  Prevent signal tricks: */
      for(i = 0; i < NSIG; i++) {
	    if(i != SIGKILL && i != SIGCHLD) {
		  (void) signal(i, SIG_IGN);
	    }
      }
	
      /* Prevent file descriptor tricks; close all but stdin, out, & err: */
      for(i = getdtablesize(); i > 2; i--) {
	    (void) close(i);
      }
	    

      uid = getuid();
      euid = geteuid();

      (void) printf("uid: %d\n", uid);
      (void) printf("euid: %d\n", euid);


      if(euid != 0) {
	    (void) fprintf(stderr, "This program must be setuid root.\n");
	    exit(1);
      }

      uid_ent = getpwuid(uid);

      if(strcmp(uid_ent->pw_name, trusted_user)) {
	    (void) fprintf(stderr, "Only %s may run this program.\n",
			   trusted_user);
	    exit(1);
      }


      /* Force execution of the proper mount: */
      argv[0] = "/usr/etc/mount";


      (void) printf("argv: ");
      for(p = argv; *p != (char *)0; p++) {
	    (void) printf("[%s] ", *p);
      }
      (void) puts("");
      
      switch(pid = fork()) {
	  case -1:
	    return -1;

	  case 0:  /* child! */
	    (void) execve(argv[0], argv, trusted_env);

	    _exit(1);  /* Didn't execute! */
	    
	  default:  /* parent! */
	    break;
      }

      pid = wait(&status);

      if(WIFEXITED(status)) {
	    (void) fprintf(stderr, "child pid %d exited w/code %d\n",
			   pid, WEXITSTATUS(status));
      } else if(WIFSIGNALED(status)) {
	    (void) fprintf(stderr, "child pid %d recv'd signal %d\n",
			   pid, WTERMSIG(status));
      } else {
	    fprintf(stderr, "child did something else!\n");
      }
}