[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: setgid-wrapper



First, a retraction:

James Damour wrote:
On Tue, 2004-05-18 at 09:03, Steven Augart wrote:
As you probably know, when a shell sees that it is running a setuid or setgid shell script, it detects this because the euid and ruid or egid and rgid are different. It "fixes" this by setting the euid to be the same as the ruid, and/or egid the same as the rgid, effectively turning off the setuid/setgid bit.

Actually, I didn't know that.  Thanks for the info!

Jeroen van Wolffear wrote:
Huh? This is wrong. It is the kernel who refuses to set the UID or GID
on execution of setuid/gid shell scripts.

and Grzegorz Prokopski wrote:
When you execute a shell script it is *not* shell that actually gets
started BUT the interpreter listed in the first line.

Thanks, Jeroen and Greg, for explaining what actually goes on.  James,
I apologize for misinforming you.

Jeroen van Wolffear wrote:

> Where did you read that?

It probably started from programming on 2.9 BSD and 4.2 BSD
and 4.3 BSD Unix systems, where (if I recall correctly) setuid
shell scripts worked.

I have spent the past four years confused on this issue, mislead by the
discussion of the -p flag on the Bash 2.05b manual page:

  Turning this option off causes the effective user and group ids
  to be set to the real user and group ids.

Now I know why I had such trouble getting setuid programs to work
on Linux.

My understanding of Greg and Jeroen's explanations is that the kernel
ignores whether an interpreted program has the setuid bit set -- it
just executes the interpreter given after the #!, passing the full
pathname of the file containing interpreted program as the first argument.
If the interpreter wants to then go ahead and look at the setuid or
setgid bits on the file it was given as the first argument, the way
perl and suidperl do, that's the interpreter's business.

I've written a little program to test and demonstrate this to myself,
"whoarewe.c", attached.  (It is like "whoami" and "id", except that it
ignores the first and subsequent arguments).  So I can make it the
"interpreter" for a setgid interpreted script and get useful output:

   -rwxrwsr-x    1 augart   games          57 19 mag 15:33 whoarewe-interpreter.whoarewe
   @augart-tp23: ~ $ cat whoarewe-interpreter.whoarewe
   #! /home/augart/.bin/whoarewe
   This text will be ignored.
   @augart-tp23: ~ $

Second, a reply on the main topic:

James Damour wrote:
[ a lot of good ideas followed by the question: ]
Should I take the first crack at writing setguid-wrapper?

Please do so.

Should we
pass the concept by Debian Security first?

I like Greg Prokopski's idea of writing the code first, and then when
you (we?) have a sample ready to go, writing to debian-security with
a description of the (debugged) approach and a request for feedback.
After the revised(?) approach has no more problems and is implemented,
write up all of the user documentation and ask debian-security for
feedback on that, to see if there are ways someone might misinterpret
the docs and do something dangerous.

I had suggested restricting the program to just being a setgid
wrapper at first, because it seemed harder to exploit security
bugs that way.  I know that that once one gains setgid access to
the "disk" group, one can then go ahead and directly modify the
raw filesystem to change the permissions, but that at least
requires a fair amount of sophistication.  If someone manages
to break into the group "games" and take away my Tetris high score,
I'll survive the loss.

I anticipate a couple of rounds with debian-security before
the issue is settled.

--
Steven Augart

Jikes RVM, a free runtime system for Java:
http://oss.software.ibm.com/jikesrvm
/* -*-coding: iso-8859-15-*-

   Demo program to test how the kernel launches shell scripts.  Shows the
   current real and effective UIDs and GIDs.  Ignores its arguments.
*/

/* Author: Steven Augart
   Based on "become.c", copyright © 1999, 2000, 2003, 2004 by Steven Augart.

   This code is quadruply-licensed free software, CPL 1.0/MPL 1.1/GPL 2.0/LGPL
   2.1. License terms are at the bottom of this file.
*/

#define _GNU_SOURCE		/* Enable strdupa() */
#include <stdlib.h>		/* exit() */
#include <unistd.h>		/* getuid(), geteuid(), getgid(), getegid() */
#include <sys/types.h>		/* gid_t, uid_t */
#include <stdio.h>
#include <ctype.h>		/* isdigit() */
#include <pwd.h>		/* getpwuid() */
#include <grp.h>		/* getgrgid() */
#include <errno.h>
#include <assert.h>
#include <string.h>		/* strcpy(), strcmp(), strdupa() */

const char *Me;			/* Name of this program. */

static void show(const char caption[], const char name[], int idnum);

int
main(int argc __attribute__((unused)), char **argv)
{
    Me = strrchr(argv[0], '/');
    if (Me)			/* trim trailing slash, if any. */
	++Me;
    else
	Me = argv[0];

    uid_t ruid = getuid(), euid = geteuid();
    errno = 0;
    struct passwd *tmp_pw = getpwuid(ruid);
    char *ruidname = strdupa(tmp_pw ? tmp_pw->pw_name : "");
    tmp_pw = getpwuid(euid);
    char *euidname = strdupa(tmp_pw ? tmp_pw->pw_name : "");

    gid_t rgid = getgid(), egid = getegid();
    struct group *tmp_grp = getgrgid(rgid);
    char *rgidname = strdupa(tmp_grp ? tmp_grp->gr_name : "");
    tmp_pw = getpwuid(euid);
    char *egidname = strdupa(tmp_grp ? tmp_grp->gr_name : "");

    if (errno) {
	fprintf(stderr, 
		"%s: getpwuid() or getpwgid() failed: %s\n", Me,
		strerror(errno));
	assert(errno == ENOMEM);
	exit(1);
    }
	
    show("Real uid", ruidname, ruid);
    show("Effective uid", euidname, euid);
    show("Real gid", rgidname, rgid);
    show("Effective gid", egidname, egid);
    exit(0);
}

static void show(const char caption[], const char name[], int idnum)
{
    printf("%15s: %s%s%d%s\n",
	   caption, name, name ? "(" : "#", idnum, name ? ")" : "");
}



/* This software may be freely used and redistributed under the Common Public
   License, version 0.5 or later.

   Alternatively, the contents of this file may be used under the terms of
   the GNU General Public License Version 2 or later (the "GPL"), or
   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), or
   the Mozilla Public License Version 1.1 or later (the "MPL"), in which case
   the provisions of the GPL or the LGPL or MPL are applicable instead.
 
   If you wish to allow use of your version of this file only under the terms
   of some subset of the above four licenses, indicate your decision by
   deleting the provisions above and replace them with a notice and other
   provisions indicating which licences you choose.  If you do not delete the
   provisions above, a recipient may use your version of this file under the
   terms of any one of the CPL, the MPL, the GPL, or the LGPL. */

Reply to: