Skip to contentSkip to conversation

Issues with seteuid()?

parisc-linux Luigi Gangitano 4 participants 7 messages Jan 12, 2003 – Feb 19, 2003

lore
Share & tools
lore
#0 lore raw

Hi all,
I'm the Debian package maintainer for Squid (HTTP Proxy). I received the forwarded bug report describing issues in seteuid() on palinux. While using seteuid(), forked processes terminate with SEGV.

Is it a known problem?

Thanks.

L

Please CC: me, I'm not subscribed to this list.

-----Forwarded Message-----

Quoted 18 lines

This small mail to mentionned that I reach to make squid operational on a linux-2.4.20-pa17 thanks to the following tips:

in debian rules replace statement

    ac_cv_func_setresuid=no \
by
    ac_cv_func_setresuid=yes \

so that function leave_suid() [into src/tools.c] will use setresuid() in place of seteuid() before launch fork().

Is it a know problem on palinux?

Greetings,
Joel

PS: Luigi, I also test it on 2.5.1 and it works also for parisc linux (testing config). HTH

Signature · 2 lines
 Luigi Gangitano -- <[email protected]> -- <[email protected]>
 GPG: 1024D/924C0C26: 12F8 9C03 89D3 DB4A 9972  C24A F19B A618 924C 0C26
#1 lore raw
Quoted 5 lines · Luigi Gangitano

I'm the Debian package maintainer for Squid (HTTP Proxy). I received the forwarded bug report describing issues in seteuid() on palinux. While using seteuid(), forked processes terminate with SEGV.

Is it a known problem?

I wonder how it can be a problem at all. The kernel implements only sys_setresuid() and i would imagine that glibc implements both seteuid() and setresuid() in terms of this system call.

Perhaps someone who's willing to touch glibc would care to comment?

Signature · 3 lines
"It's not Hollywood.  War is real, war is primarily not about defeat or
victory, it is about death.  I've seen thousands and thousands of dead bodies.
Do you think I want to have an academic debate on this subject?" -- Robert Fisk
#2 lore raw
Quoted 5 lines

I wonder how it can be a problem at all. The kernel implements only sys_setresuid() and i would imagine that glibc implements both seteuid() and setresuid() in terms of this system call.

Perhaps someone who's willing to touch glibc would care to comment?

seteuid() works fine in simple tests. i don't think it's seteuid... something else is broken. can someone provide a simple test case for the segfault?

randolph

Signature · 3 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
#3 lore raw

Hi Randolph,

As per your request, I do spent some time to compose this 'small' test case bases on simplified parts of squid:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/* getpid(), geteuid() */
#include <sys/types.h>
#include <unistd.h>

/* setgroups() */
#include <grp.h>

/* mkdir() */
#include <sys/stat.h>
#define MAXPATHLEN 256

/* waitpid() */
#include <sys/wait.h>

char *effectiveUser="proxy";
uid_t effectiveUserID=13;
gid_t effectiveGroupID=13;

/* Define if you have the setgroups function. */
#define HAVE_SETGROUPS 1

/*
* Yay! Another Linux brokenness. Its not good enough to know that
* setresuid() exists, because RedHat 5.0 declare setresuid() but
* doesn't implement it.
*/
#define HAVE_SETRESUID 1

#undef HAVE_SETRESUID
/*
*/

/*
man setresuid NOTES:
Under HP-UX and FreeBSD the prototype is found in <unistd.h>.
Under
Linux there is so far no include file giving the prototype - this
is a
glibc bug. Programs using this system call must add the prototype
them-
selves.
*/
#ifdef HAVE_SETRESUID
/* because man setresuid mentionned it as a lake of linux? */ int
setresuid(uid_t ruid, uid_t euid, uid_t suid);
#endif

/* Define if you have the seteuid function. */
#define HAVE_SETEUID 1

/*
* xstrerror() - strerror() wrapper
*/
const char *
xstrerror(void)

{
    static char xstrerror_buf[BUFSIZ];
    static char strerror_buf[BUFSIZ];

    snprintf(strerror_buf, BUFSIZ, "%s", strerror(errno));
   
    if (strerror_buf) 
	snprintf(xstrerror_buf, BUFSIZ, "(%d) %s", errno, strerror_buf);
    else
        snprintf(xstrerror_buf, BUFSIZ, "(%d) Unknown", errno); 
    return xstrerror_buf;
}

/* leave a privilegied section. (Give up any privilegies)
* Routines that need privilegies can rap themselves in enter_suid()
* and leave_suid()
* To give upp all posibilites to gain privilegies use no_suid() */
void
leave_suid(void)

{
    fprintf(stderr, "leave_suid: PID %d called\n", (int) getpid());
    if (geteuid() != 0)
	return;
    /* Started as a root, check suid option */
    if (effectiveUser == NULL)
	return;
#if HAVE_SETGROUPS
    setgroups(1, &effectiveGroupID);

#endif
if (setgid(effectiveGroupID) < 0)
fprintf(stderr, "ALERT: setgid: %s\n", xstrerror());
fprintf(stderr, "leave_suid: PID %d giving up root, becoming '%s'\n",
(int) getpid(), effectiveUser);
#if HAVE_SETRESUID
if (setresuid(effectiveUserID, effectiveUserID, 0) < 0)
fprintf(stderr, "ALERT: setresuid: %s\n", xstrerror());
#elif HAVE_SETEUID
if (seteuid(effectiveUserID) < 0)
fprintf(stderr, "ALERT: seteuid: %s\n", xstrerror());
#else
if (setuid(effectiveUserID) < 0)
fprintf(stderr, "ALERT: setuid: %s\n", xstrerror());
#endif
}

static void
setEffectiveUser(void)

{
    leave_suid();		/* Run as non privilegied user */
    if (geteuid() == 0) {
	fprintf(stderr, "Squid is not safe to run as root!  If you must\n");
	fprintf(stderr, "start Squid as root, then you must configure\n");
	fprintf(stderr, "it to run as a non-priveledged user with the\n");
	fprintf(stderr, "'cache_effective_user' option in the config file.\n");
	fprintf(stderr, "Don't run Squid as root, set 'cache_effective_user'!\n");
        abort();
    }
}

static int
storeUfsDirCreateDirectory(const char *path)

{
    int created = 0;

    if (0 != mkdir(path, 0755)) {
	fprintf(stderr,	"Failed to make swai directory %s: %s\n",
	    path, xstrerror());
    }
    return created;
}

static void
storeUfsDirCreateSwapSubDirs(char * Path)

{
    int i, k;
    static char name[MAXPATHLEN];
    for (i = 0; i < 16; i++) {
	snprintf(name, MAXPATHLEN, "%s/%02X", Path, i);
        storeUfsDirCreateDirectory(name);
	fprintf(stderr, "Making directories in %s\n", name);
	for (k = 0; k < 32; k++) {
	    snprintf(name, MAXPATHLEN, "%s/%02X/%02X", Path, i, k);
            storeUfsDirCreateDirectory(name);
	}
    }
}

static void
storeUfsDirNewfs(char * Path)

{
    fprintf(stderr, "Creating swap space in %s\n", Path);
    storeUfsDirCreateSwapSubDirs(Path);
}

void
storeCreateSwapDirectories(void)

{
    int i;
    pid_t pid;
    int status;
    for (i = 0; i < 1; i++) {
	if (fork())
	    continue;
        storeUfsDirNewfs("/var/spool/squid");
	exit(0);
    }
    do {
	pid = waitpid(-1, &status, 0);
    } while (pid > 0 || (pid < 0 && errno == EINTR));
}

int
main(int argc, char **argv)

{
    /* only opt_create_swap_dirs */

    setEffectiveUser();
    fprintf(stderr, "Creating Swap Directories\n");
    storeCreateSwapDirectories();

    return 0;
}

A. On a testing debian system (ie gcc-3.0 3.0.4-10 && libc6 2.2.5-14.3) and the very last kernel 2.4.20-pa23:

Compile with gcc -O 2 -Wall -D_REENTRANT foo.c -o foo

[ Create a user and a group named proxy with id 13 for both ]

First as it is ./foo would failled to fork() immediately with 'Segmentation fault'.

Secondly edit foo.c to comment out #undifined HAVE_SETRESUID; it would reach to fork without problem (eventhough it did not reach to create dir)

B. On an unstable debian (ie gcc-3.2 3.2.2-0pre6 && libc6 2.3.1-10) running the same kernel: this problem doesn't occure.

hth,
Joel

Quoted 14 lines

-- Original Message --
From: Randolph Chung <[email protected]>
To: Matthew Wilcox <[email protected]>
Cc: Luigi Gangitano <[email protected]>,
[email protected]
Subject: Re: [parisc-linux] Issues with seteuid()?
Reply-To: Randolph Chung <[email protected]>
Date: Sun, 12 Jan 2003 19:11:09 -0800

Quoted 4 lines

I wonder how it can be a problem at all. The kernel implements only sys_setresuid() and i would imagine that glibc implements both seteuid() and setresuid() in terms of this system call.

Quoted 15 lines
Quoted 1 line

Perhaps someone who's willing to touch glibc would care to comment?

seteuid() works fine in simple tests. i don't think it's seteuid... something else is broken. can someone provide a simple test case for the segfault?

randolph

Signature · 7 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

*********************************************
Vous surfez toujours avec une ligne classique ?
Faites des economies avec Tiscali Complete...
Plus d'info sur ... http://complete.tiscali.be

#4 lore raw
Quoted 9 lines

A. On a testing debian system (ie gcc-3.0 3.0.4-10 && libc6 2.2.5-14.3) and the very last kernel 2.4.20-pa23:

Compile with gcc -O 2 -Wall -D_REENTRANT foo.c -o foo

[ Create a user and a group named proxy with id 13 for both ]

First as it is ./foo would failled to fork() immediately with 'Segmentation fault'.

# uname -a
Linux legolas 2.4.20-pa23 #110 Mon Jan 27 23:44:18 PST 2003 parisc unknown unknown GNU/Linux
ii  gcc-3.0        3.0.4-7        The GNU C compiler.
ii  libc6          2.2.5-14.3     GNU C Library: Shared libraries and Timezone
# gcc-3.0 -O2 -Wall -D_REENTRANT seteuid.c -o seteuid
# ./seteuid
leave_suid: PID 18443 called
leave_suid: PID 18443 giving up root, becoming 'proxy'
Creating Swap Directories
[....]

no segfault...

can you maybe run it with strace and send the last few lines of output?

randolph

Signature · 3 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
#5 lore raw

Randolph,

Quoted 27 lines
Quoted 3 lines

A. On a testing debian system (ie gcc-3.0 3.0.4-10 && libc6 2.2.5-14.3)

and

Quoted 8 lines

the very last kernel 2.4.20-pa23:

Compile with gcc -O 2 -Wall -D_REENTRANT foo.c -o foo

[ Create a user and a group named proxy with id 13 for both ]

First as it is ./foo would failled to fork() immediately with 'Segmentation fault'.

# uname -a
Linux legolas 2.4.20-pa23 #110 Mon Jan 27 23:44:18 PST 2003 parisc unknown
unknown GNU/Linux
ii  gcc-3.0        3.0.4-7        The GNU C compiler.
ii  libc6          2.2.5-14.3     GNU C Library: Shared libraries and Timezone
# gcc-3.0 -O2 -Wall -D_REENTRANT seteuid.c -o seteuid
# ./seteuid
leave_suid: PID 18443 called
leave_suid: PID 18443 giving up root, becoming 'proxy'
Creating Swap Directories
[....]
Quoted 4 lines

no segfault...

can you maybe run it with strace and send the last few lines of output?

Well so short that I can give you all:

ii  gcc-3.0        3.0.4-10       The GNU C compiler.
ii  gcc-3.0-base   3.0.4-10       The GNU Compiler Collection (base package).
ii  libc6          2.2.5-14.3     GNU C Library: Shared libraries and Timezone
# strace -f ./a.out
execve("./a.out", ["./a.out"], [/* 18 vars */]) = 0
newuname({sys="Linux", node="fw01.office.palinux", ...}) = 0
brk(0)                                  = 0x26000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
= 0x40017000
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=0, st_size=0, ...}) = 0
mmap(NULL, 16726, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40018000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\2\1\3\0\0\0\0\0\0\0\0\0\3\0\17\0\0\0\1\0\2\37"..., 1024)
= 1024
fstat64(3, {st_mode=0, st_size=0, ...}) = 0
mmap(NULL, 1392404, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40028000
mprotect(0x4015f000, 118548, PROT_NONE) = 0
mmap(0x4016e000, 45056, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED,
3, 0x136000) = 0x4016e000
mmap(0x40179000, 12052, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,
-1, 0) = 0x40179000
close(3)                                = 0
munmap(0x40018000, 16726)               = 0
getpid()                                = 25520
write(2, "leave_suid: PID 25520 called\n", 29leave_suid: PID 25520 called
) = 29
geteuid()                               = 0
setgroups(1, [13])                      = 0
setgid(13)                              = 0
getpid()                                = 25520
write(2, "leave_suid: PID 25520 giving up "..., 55leave_suid: PID 25520 giving
up root, becoming 'proxy'
) = 55
setresuid(ruid 4294967295, euid 13, suid 4294967295) = 0
geteuid()                               = 13
write(2, "Creating Swap Directories\n", 26Creating Swap Directories
) = 26
fork()                                  = -1 EAGAIN (Resource temporarily
unavailable)
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++

Well as explained in a previous mail if I do a su - proxy and launch same program no problem to fork() ??

Thanks for your attention,
Joel

*********************************************
Vous surfez toujours avec une ligne classique ?
Faites des economies avec Tiscali Complete...
Plus d'info sur ... http://complete.tiscali.be

#6 lore raw
In reply to Luigi Gangitano

Hi all,

Here is a 'small' test case which reproduce the problem on a sarge (ie testing) debian (gcc-3.0_3.0.4-12; libc6_2.2.5-14.3) running very last kernel 2.4.20-pa23:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/* getpid(), geteuid() */
#include <sys/types.h>
#include <unistd.h>

/* setgroups() */
#include <grp.h>

/* mkdir() */
#include <sys/stat.h>
#define MAXPATHLEN 256

/* waitpid() */
#include <sys/wait.h>

char *effectiveUser="proxy";
uid_t effectiveUserID=13;
gid_t effectiveGroupID=13;

/* Define if you have the setgroups function. */
#define HAVE_SETGROUPS 1

/*
* Yay! Another Linux brokenness. Its not good enough to know that
* setresuid() exists, because RedHat 5.0 declare setresuid() but
* doesn't implement it.
*/
#define HAVE_SETRESUID 1

#undef HAVE_SETRESUID
/*
*/

/*
man setresuid NOTES:
Under HP-UX and FreeBSD the prototype is found in <unistd.h>.
Under
Linux there is so far no include file giving the prototype - this
is a
glibc bug. Programs using this system call must add the prototype
them-
selves.
*/
#ifdef HAVE_SETRESUID
int
setresuid(uid_t ruid, uid_t euid, uid_t suid);
#endif

/* Define if you have the seteuid function. */
#define HAVE_SETEUID 1

/*
* xstrerror() - strerror() wrapper
*/
const char *
xstrerror(void)

{
    static char xstrerror_buf[BUFSIZ];
    static char strerror_buf[BUFSIZ];

    snprintf(strerror_buf, BUFSIZ, "%s", strerror(errno));
   
    if (strerror_buf) 
	snprintf(xstrerror_buf, BUFSIZ, "(%d) %s", errno, strerror_buf);
    else
        snprintf(xstrerror_buf, BUFSIZ, "(%d) Unknown", errno); 
    return xstrerror_buf;
}

/* leave a privilegied section. (Give up any privilegies)
* Routines that need privilegies can rap themselves in enter_suid()
* and leave_suid()
* To give upp all posibilites to gain privilegies use no_suid() */
void
leave_suid(void)

{
    fprintf(stderr, "leave_suid: PID %d called\n", (int) getpid());
    if (geteuid() != 0)
	return;
    /* Started as a root, check suid option */
    if (effectiveUser == NULL)
	return;
#if HAVE_SETGROUPS
    setgroups(1, &effectiveGroupID);

#endif
if (setgid(effectiveGroupID) < 0)
fprintf(stderr, "ALERT: setgid: %s\n", xstrerror());
fprintf(stderr, "leave_suid: PID %d giving up root, becoming '%s'\n",
(int) getpid(), effectiveUser);
#if HAVE_SETRESUID
if (setresuid(effectiveUserID, effectiveUserID, 0) < 0)
fprintf(stderr, "ALERT: setresuid: %s\n", xstrerror());
#elif HAVE_SETEUID
if (seteuid(effectiveUserID) < 0)
fprintf(stderr, "ALERT: seteuid: %s\n", xstrerror());
#else
if (setuid(effectiveUserID) < 0)
fprintf(stderr, "ALERT: setuid: %s\n", xstrerror());
#endif
}

static void
setEffectiveUser(void)

{
    leave_suid();		/* Run as non privilegied user */
    if (geteuid() == 0) {
	fprintf(stderr, "Squid is not safe to run as root!  If you must\n");
	fprintf(stderr, "start Squid as root, then you must configure\n");
	fprintf(stderr, "it to run as a non-priveledged user with the\n");
	fprintf(stderr, "'cache_effective_user' option in the config file.\n");
	fprintf(stderr, "Don't run Squid as root, set 'cache_effective_user'!\n");
        abort();
    }
}

static int
storeUfsDirCreateDirectory(const char *path)

{
    int created = 0;

    if (0 != mkdir(path, 0755)) {
	fprintf(stderr,	"Failed to make swai directory %s: %s\n",
	    path, xstrerror());
    }
    return created;
}

static void
storeUfsDirCreateSwapSubDirs(char * Path)

{
    int i, k;
    static char name[MAXPATHLEN];
    for (i = 0; i < 16; i++) {
	snprintf(name, MAXPATHLEN, "%s/%02X", Path, i);
        storeUfsDirCreateDirectory(name);
	fprintf(stderr, "Making directories in %s\n", name);
	for (k = 0; k < 32; k++) {
	    snprintf(name, MAXPATHLEN, "%s/%02X/%02X", Path, i, k);
            storeUfsDirCreateDirectory(name);
	}
    }
}

static void
storeUfsDirNewfs(char * Path)

{
    fprintf(stderr, "Creating swap space in %s\n", Path);
    storeUfsDirCreateSwapSubDirs(Path);
}

void
storeCreateSwapDirectories(void)

{
    int i;
    pid_t pid;
    int status;
    for (i = 0; i < 1; i++) {
	if (fork())
	    continue;
        storeUfsDirNewfs("/var/spool/squid");
	exit(0);
    }
    do {
	pid = waitpid(-1, &status, 0);
    } while (pid > 0 || (pid < 0 && errno == EINTR));
}

int
main(int argc, char **argv)

{
    /* only opt_create_swap_dirs */

    setEffectiveUser();
    fprintf(stderr, "Creating Swap Directories\n");
    storeCreateSwapDirectories();

    return 0;
}

(rebuild from simplified parts of squid-2.5 src)

compile with: gcc -O 2 -Wall -D_REENTRANT file.c -o ct

[create a user and a group named proxy with id 13 both]

compile as it is it, it will failled immediately with 'Segmentation fault'

edit sources to comment out '#undef HAVE_SETRESUID' line, recompile with same option and it would fork without problem (even thought it will failled to actually create dir)

hth,
Joel

PS: this test case doesn't present the same pb on an unstable debian (ie compile with gcc-3.2_3.2.2-0pre6 & libc6_2.3.1-10). I try this on the same kernel running each the two different install.

Quoted 15 lines

-- Original Message --
From: Luigi Gangitano <[email protected]>
To: [email protected]
Subject: [parisc-linux] Issues with seteuid()?
Date: 12 Jan 2003 16:49:29 +0100

Hi all,
I'm the Debian package maintainer for Squid (HTTP Proxy). I received the forwarded bug report describing issues in seteuid() on palinux. While using seteuid(), forked processes terminate with SEGV.

Is it a known problem?

Quoted 16 lines

Thanks.

L

Please CC: me, I'm not subscribed to this list.

-----Forwarded Message-----

Quoted 9 lines

This small mail to mentionned that I reach to make squid operational on a linux-2.4.20-pa17 thanks to the following tips:

in debian rules replace statement

    ac_cv_func_setresuid=no \
by
    ac_cv_func_setresuid=yes \

so that function leave_suid() [into src/tools.c] will use setresuid()

in

Quoted 8 lines
Quoted 8 lines

place of seteuid() before launch fork().

Is it a know problem on palinux?

Greetings,
Joel

PS: Luigi, I also test it on 2.5.1 and it works also for parisc linux

(testing

Quoted 8 lines
Quoted 1 line

config). HTH

Signature · 4 lines
Luigi Gangitano -- <[email protected]> -- <[email protected]>
GPG: 1024D/924C0C26: 12F8 9C03 89D3 DB4A 9972  C24A F19B A618 924C 0C26

Attachment: signature.asc

*********************************************
Vous surfez toujours avec une ligne classique ?
Faites des economies avec Tiscali Complete...
Plus d'info sur ... http://complete.tiscali.be