Return-Path: 
 <bounce=bounce-debian-devel#=peter_e#=gmx.net#alists.debian.org=152=56d5=peter_e@gmx.net>
X-Original-To: peter@pezone.net
Delivered-To: peter@pezone.net
Received: from localhost (localhost.localdomain [127.0.0.1])
	by ramrod.pezone.net (Postfix) with ESMTP id 943AB3C0020
	for <peter@pezone.net>; Mon, 26 Jul 2004 06:55:04 +0200 (CEST)
Received: from ramrod.pezone.net ([127.0.0.1])
	by localhost (ramrod.pezone.net [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id 05941-08 for <peter@pezone.net>;
	Mon, 26 Jul 2004 06:55:04 +0200 (CEST)
Received: from mx0.gmx.net (mx0.gmx.net [213.165.64.100])
	by ramrod.pezone.net (Postfix) with SMTP id 69C673C0013
	for <peter@pezone.net>; Mon, 26 Jul 2004 06:55:04 +0200 (CEST)
Received: (qmail 14685 invoked by alias); 26 Jul 2004 04:55:04 -0000
Delivered-To: GMX delivery to peter_e@gmx.net
Received: (qmail 14614 invoked by uid 65534); 26 Jul 2004 04:55:03 -0000
Received: from murphy.debian.org (EHLO murphy.debian.org) (146.82.138.6)
	by mx0.gmx.net (mx006) with SMTP; 26 Jul 2004 06:55:03 +0200
Received: from localhost (localhost [127.0.0.1])
	by murphy.debian.org (Postfix) with QMQP
	id 002E3F133; Sun, 25 Jul 2004 23:54:06 -0500 (CDT)
Old-Return-Path: <russell@coker.com.au>
X-Original-To: debian-devel@lists.debian.org
Received: from smtp.sws.net.au (smtp.sws.net.au [61.95.69.6])
	by murphy.debian.org (Postfix) with ESMTP
	id 60F72F129; Sun, 25 Jul 2004 23:53:57 -0500 (CDT)
Received: from localhost (localhost [127.0.0.1])
	by smtp.sws.net.au (Postfix) with ESMTP id 92F4061CA1;
	Mon, 26 Jul 2004 14:54:00 +1000 (EST)
Received: from smtp.sws.net.au ([127.0.0.1])
	by localhost (smtp [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
	id 01992-10; Mon, 26 Jul 2004 14:54:00 +1000 (EST)
Received: from lyta.coker.com.au (localhost [127.0.0.1])
	by smtp.sws.net.au (Postfix) with ESMTP id EAD9161C9F;
	Mon, 26 Jul 2004 14:53:59 +1000 (EST)
Received: from localhost (localhost [127.0.0.1])
	by lyta.coker.com.au (Postfix) with ESMTP id B1D8BB59A6;
	Mon, 26 Jul 2004 14:53:57 +1000 (EST)
From: Russell Coker <russell@coker.com.au>
Reply-To: russell@coker.com.au
Subject: init scripts and su
Date: Mon, 26 Jul 2004 14:53:56 +1000
User-Agent: KMail/1.6.2
To: debian-devel@lists.debian.org
Cc: debian-security@lists.debian.org
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
  boundary="Boundary-00=_k5IBBE2GPW9IlXo"
Message-Id: <200407261453.56729.russell@coker.com.au>
X-Virus-Scanned: by amavisd-new-20030616-p10 (Debian) at sws.net.au
X-Rc-Virus: 2004-07-20_01
X-Rc-Spam: 2004-07-19_01
X-Spam-Checker-Version: SpamAssassin 2.63-lists.debian.org_2004_07_08_01
	(2004-01-11) on murphy.debian.org
X-Spam-Status: No, hits=-3.7 required=4.0 tests=IMPRONONCABLE_1,
 LDOSUBSCRIBER,
	MURPHY_WRONG_WORD1,MURPHY_WRONG_WORD2 autolearn=no
	version=2.63-lists.debian.org_2004_07_08_01
Resent-Message-ID: <ltwsKD.A.JUD.u5IBBB@murphy>
Resent-From: debian-devel@lists.debian.org
X-Mailing-List: <debian-devel@lists.debian.org> archive/latest/174875
X-Loop: debian-devel@lists.debian.org
List-Id: <debian-devel.lists.debian.org>
List-Post: <mailto:debian-devel@lists.debian.org>
List-Help: <mailto:debian-devel-request@lists.debian.org?subject=help>
List-Subscribe: 
 <mailto:debian-devel-request@lists.debian.org?subject=subscribe>
List-Unsubscribe: 
 <mailto:debian-devel-request@lists.debian.org?subject=unsubscribe>
List-Archive: <http://lists.debian.org/debian-devel/>
Precedence: list
Resent-Sender: debian-devel-request@lists.debian.org
Resent-Date: Sun, 25 Jul 2004 23:54:06 -0500 (CDT)
X-GMX-Antispam: -2 (not scanned, spam filter disabled)
X-Resent-By: Forwarder <forwarder@gmx.net>
X-Resent-For: peter_e@gmx.net
X-Resent-To: peter@pezone.net
X-UID: 11591

--Boundary-00=_k5IBBE2GPW9IlXo
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Subject: 

The start scripts for some daemons do "su - user" or use
"start-stop-daemon -c" to launch the daemon, postgresql is one example.

During the time between the daemon launch and it closing it's file handles and 
calling setsid(2) (which some daemons don't do because they are buggy) any 
other code running in the same UID could take over the process via ptrace, 
fork off a child process that inherits the administrator tty, and then stuff 
characters into the keyboard buffer with ioctl(fd,TIOCSTI,&c) (*).

To address these issues for Fedora I have written a program named init_su.

init_su closes all file handles other than 1 and 2 (stdout and stderr).  File
handles 1 and 2 are fstat()'d, if they are regular files or pipes then they
are left open (no attack is possible through a file or pipe), otherwise they
are closed and /dev/null is opened instead.  /dev/null is opened for file
handle 0 regardless of what it might have pointed to previously.  Then
setsid() is called to create a new session for the process (make it a group
leader), this invalidates /dev/tty.  Then the uid is changed and the daemon
is started.


I have attached the source code to init_su, please check it out and tell me
what you think.  After the discussion concludes I will write a patch for 
start-stop-daemon to give similar functionality.


(*)  On system boot and shutdown there is no problem.  It's when the
administrator uses /etc/init.d/postgresql to start or stop the database that
there is potential for attack.


http://www.redhat.com/archives/fedora-devel-list/2004-July/msg01314.html

I have also started a similar discussion on the Fedora development list about 
this issue, see the above URL.

--
http://www.coker.com.au/selinux/   My NSA Security Enhanced Linux packages
http://www.coker.com.au/bonnie++/  Bonnie++ hard drive benchmark
http://www.coker.com.au/postal/    Postal SMTP/POP benchmark
http://www.coker.com.au/~russell/  My home page

--Boundary-00=_k5IBBE2GPW9IlXo
Content-Type: text/x-csrc;
  charset="us-ascii";
  name="init_su.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="init_su.c"

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>

void usage(const char * const msg)
{
  if(msg)
    fprintf(stderr, "Error: %s\n\n", msg);
  fprintf(stderr, "Usage: init_su [-l] user -c command\n");
  exit(1);
}

int main(int argc, char **argv)
{
  int i, fd;
  int login = 0;
  char *command = NULL, *user = NULL, *shell = NULL, *nu_argv[4];
  struct passwd *pw;

  int int_c = 0;
  while(int_c != -1)
  {
    int_c = getopt(argc, argv, "-lc:s:");
    switch(int_c)
    {
      case 1:
        if(!strcmp(optarg, "-"))
        {
          login = 1;
        }
        else
        {
          user = optarg;
        }
      break;
      case 'l':
        login = 1;
      break;
      case 's':
        shell = optarg;
      break;
      case 'c':
        command = optarg;
      break;
    }
  }
  if(!user || !command)
    usage(NULL);
  pw = getpwnam(user);
  if(!pw)
    usage("User unknown.");
  if(setregid(pw->pw_gid, pw->pw_gid))
    usage("Can't setgid(), are you root?");
  if(setreuid(pw->pw_uid, pw->pw_uid))
    usage("Can't setuid(), are you root?");
  if(!shell)
    shell = pw->pw_shell;
  if(login)
  {
    nu_argv[0] = strrchr(shell, '/');
    if(!nu_argv[0])
      usage("Bad shell.");
    nu_argv[0] = strdup(nu_argv[0]);
    nu_argv[0][0] = '-';
  }
  else
    nu_argv[0] = shell;
  nu_argv[1] = "-c";
  nu_argv[2] = command;
  nu_argv[3] = NULL;
  close(0);
  for(i = 3; i < 1024; i++)
    close(i);
  openlog("initrc_su", LOG_CONS | LOG_NOWAIT, LOG_DAEMON);
  fd = open("/dev/null", O_RDWR);
  if(fd == -1)
  {
    syslog(LOG_ERR, "Can't open /dev/null when trying to execute program %s", command);
    return 1;
  }
  for(i = 0; i < 3; i++)
  {
    struct stat sbuf;
    if(i != fd && (fstat(i, &sbuf) == -1 || (!S_ISREG(sbuf.st_mode) && !S_ISFIFO(sbuf.st_mode)) ))
    {
      close(i);
      if(dup2(fd, i) != i)
      {
        syslog(LOG_ERR, "Can't dup2() when trying to execute program %s", command);
        return 1;
      }
    }
  }
  if(fd >= 3)
    close(fd);
  setsid();  /* it's OK if this fails as we get the right result anyway */
  execv(shell, nu_argv);
  syslog(LOG_ERR, "Can't exec program %s", command);
  return 1;
}

--Boundary-00=_k5IBBE2GPW9IlXo--


-- 
To UNSUBSCRIBE, email to debian-devel-REQUEST@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org

