Mailing List Archive

setuid FROM root causes tainting
Greetings. I attempted to submit this once before, both via mail to
perlbug@perl.com and as an article in comp.lang.perl. I haven't
seen a response in either place, nor do I see my item chronicled in
the perl bugs database, so on the off chance that it got lost
somehow, I am submitting it again. Hope this isn't too pesky of
me. I know you're all quite busy and not being paid for any of this,
but I would appreciate at least an acknowledgement of receipt.
Thanks.

***

Brief summary: If you run a perl script while logged in as root,
and the script changes effective uid to something else, perl engages
its tainting mechanism, making everything difficult. Ironically,
the script was changing its uid in an attempt to be more secure and
prevent unintended alteration of protected files.

Here's my original message, describing this in more detail, and the
changes I propose to correct it:

----
I have a script which actually functions as an internet server,
listening on a privleged tcp/ip port. This script is started up at
system boot, and runs as root (actually as root, not under setuid to
root).

Because I want to try and guard against potential hacking attempts
(even though it's _extremely_ unlikely anyone could get this server
to do anything bad), I try and be a good citizen by having the script
change its effective uid to something *less* privileged. It runs in
this state most (99%) of the time; it only runs as root for the few
lines of code needed to establish the socket and bind it to the
privileged port.

This all worked under perl4, or at least under the version of perl4 I
was running (I didn't have the source code for our perl4 installation,
so I don't know what options might have been used to build it). Under
perl5, however, perl detects that, during most of the running of the
software, the real uid and the effective uid are different. It thus
wrongly concludes that I'm running it as a setuid script, and applies
the various "tainting" rules, which result in my inability to do such
mundane things as change directories. Ironically, perl tells me it
can't do this because my script is insecure, when in fact I took extra
steps to make sure the code was *more* secure.

I have fixed this in my version of perl, and I'm wondering if this fix
makes sense for the world or not. I don't see any way this could be a
problem, but then I don't know enough about unix security to be sure
there wouldn't be other side-effects of this. What I have done is
change the code which determines whether tainting is in effect. There
are about six lines scattered throughout the perl5 source that all
read:
tainting |= (euid != uid || egid != gid);
I have changed these to read:
tainting |= (uid && (euid != uid || egid != gid));
which exempts you from tainting if your real uid is actually root.
This lets you set euid (or egid) to something else without prejudice,
if you're doing so to *reduce* your privilege level rather than
increase it.

Does this seem reasonable? If it is, should I send the modified
source code somewhere? Let me know.

----

Footnote: The perl4 version where this worked was 4.036. My perl5
installation is current revision and patch level, 5.001m. Here's
my "myconfig" output:

Summary of my perl5 (patchlevel 1) configuration:
Platform:
osname=svr4, osver=, archname=i386-svr4
uname='unix_sv taz 4.2 1.1.3 i386 386at '
hint=previous
Compiler:
cc='/bin/cc', optimize='-O', ld='/bin/cc'
cppflags='-I/usr/include -I/usr/ucbinclude -DDEBUGGING'
ccflags ='-I/usr/include -I/usr/ucbinclude -DDEBUGGING'
ldflags ='-L/usr/ccs/lib -L/usr/ucblib'
stdchar='unsigned char', d_stdstdio=define, usevfork=false
voidflags=15, castflags=0, d_casti32=define, d_castneg=define
intsize=4, alignbytes=4, usemymalloc=y, randbits=15
Libraries:
so=so
libpth=/lib /usr/lib /usr/ccs/lib /usr/ucblib
libs=-lsocket -lnsl -ldbm -ldl -lld -lm -lc -lcrypt -lucb -lx
libc=/usr/ccs/lib/libc.so
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef
cccdlflags='-Kpic', ccdlflags=' ', lddlflags='-G -L/usr/ccs/lib
-L/usr/ucblib'

Thanks.

-Tony Camas
Boston Automation, Inc.
tony@bosauto.com
phone: 617-523-3999
fax: 617-523-3788
Re: setuid FROM root causes tainting [ In reply to ]
no, that's wrong. if uid != euid, then you can always set one
to the other and sneak thru security issues. it's right the way it works
now, or else i don't understand something.

--tom
Re: setuid FROM root causes tainting [ In reply to ]
At 02:18 PM 10/13/95 MDT, Tom Christiansen wrote:
>no, that's wrong. if uid != euid, then you can always set one
>to the other and sneak thru security issues. it's right the way it works
>now, or else i don't understand something.
>
>--tom

Hmm... Well, *one* of us doesn't understand something, that's for sure.
Let me expand on this a tad, and maybe we can figure out who isn't
understanding whom...

I login as root and run a perl script. Without any uid meddling, my
uid and euid are both 0. I also have free reign of the system. I can
write any file, etc., because I am root. perl doesn't interfere with
this, becuase both uid and euid are the same. I assume this is as
intended. The tainting stuff, from my understanding, seeks to prevent
setuid processes from doing naughty things, not to prevent legitimate
root users from using perl.

Now, my script sets $> (effective uid) equal to something else, say
100. I now only have access to whatever uid 100 has access to. This is
a good way for my script to keep itself from accidentally screwing up
something it shouldn't screw up. Now perl will bother me, unless I also
set $< (real UID) to 100. Under some circumstances, that's OK, but the
problem with setting both real and effective to someone else is that it's
a one-way trip. If I set $> to 100 and leave $< as 0, I can't get at
stuff that uid 100 can't get at. But, if I need to, I can set $> back
to 0, do privileged things, and then set $> back to 100. If I also set
$< to 100, though, I can't change either uid anymore (this is right,
isn't it?)

So, right now, as a script developer, I have the following choice:

(1) Don't change my euid. Leave it as root. My script can now wreak
all the havoc it wants (because I'm root), but perl won't bother it
(because real and effective are BOTH root).

(2) Change both euid and uid (to the same thing). Now I can't wreak
any havoc at all, but neither can I ever return myself to the state in
which I can wreak limited, controlled havoc.

What I want to do is change my euid to something non-threatening, thus
preventing havoc-wreaking, and then temporarily change it back to root
from time to time when I need to be root. This is, BTW, not an
uncommon thing for an Internet-related daemon process to do (popper,
the ucb POP3 deamon does this, for instance).

It seems to me that perl should seek to do one of two things:

(1) Turn on tainting any time you are able to do privileged things. In
this case, the appropriate check for tainting (ignoring the gid issue)
would simply be
tainting |= !euid
One could argue that this is a reasonable way to work, though I suspect
all manner of perl scripts designed to run as root would be broken by
this.

(2) Turn on tainting any time you are masquerading as root, even though
you are not really root. Then my proposed code would be right:
tainting |= !uid && (uid != euid)

what is actually happening is:

(3) Turn on tainting any time you are masquerading as anyone. Thus,
tainting is turned on if you are a regular Joe masquerading as root,
but also if you are root masquerading as a regular Joe.

I think (2) is what you really want, isn't it? I mean, why should perl
care if root is masquerading as an average Joe. This is a _good_ thing,
isn't it?

What am I missing?

-Tony
Re: setuid FROM root causes tainting [ In reply to ]
: no, that's wrong. if uid != euid, then you can always set one
: to the other and sneak thru security issues. it's right the way it works
: now, or else i don't understand something.

Yes, but if you force your real uid to non-root, you would not be able to
get back to root on most systems. I've installed a bug report.

Larry
Re: setuid FROM root causes tainting [ In reply to ]
No, I think that where uid == 0 and euid != 0, you should ignore
tainting. After all, the person didn't need a perl script to do
damage, they OWN the machine.

To be more general, given real security (in my small world this STARTS
with having multiple levels of authorization and privilege), taint
would only be engaged when you were running a script that had some
privilege that the user who RAN it did not. We're not trying to
protect users from trojans, here, so it makes no sense to restrict a
step-down in privilege.

-AJS
--
--- Aaron Sherman / "B4 f w+ c kv s+(--)v r p" ---
Phone: (617)321-5100 "I do not speak for THEM."
Email: ajs@ajs.com WWW: http://ajs.com/~ajs/
Re: setuid FROM root causes tainting [ In reply to ]
At 02:18 PM 10/13/95 MDT, Tom Christiansen wrote:
>no, that's wrong. if uid != euid, then you can always set one
>to the other and sneak thru security issues. it's right the way it works
>now, or else i don't understand something.
>
>--tom

Hmm... Well, *one* of us doesn't understand something, that's for sure.
Let me expand on this a tad, and maybe we can figure out who isn't
understanding whom...

I login as root and run a perl script. Without any uid meddling, my
uid and euid are both 0. I also have free reign of the system. I can
write any file, etc., because I am root. perl doesn't interfere with
this, becuase both uid and euid are the same. I assume this is as
intended. The tainting stuff, from my understanding, seeks to prevent
setuid processes from doing naughty things, not to prevent legitimate
root users from using perl.

Now, my script sets $> (effective uid) equal to something else, say
100. I now only have access to whatever uid 100 has access to. This is
a good way for my script to keep itself from accidentally screwing up
something it shouldn't screw up. Now perl will bother me, unless I also
set $< (real UID) to 100. Under some circumstances, that's OK, but the
problem with setting both real and effective to someone else is that it's
a one-way trip. If I set $> to 100 and leave $< as 0, I can't get at
stuff that uid 100 can't get at. But, if I need to, I can set $> back
to 0, do privileged things, and then set $> back to 100. If I also set
$< to 100, though, I can't change either uid anymore (this is right,
isn't it?)

So, right now, as a script developer, I have the following choice:

(1) Don't change my euid. Leave it as root. My script can now wreak
all the havoc it wants (because I'm root), but perl won't bother it
(because real and effective are BOTH root).

(2) Change both euid and uid (to the same thing). Now I can't wreak
any havoc at all, but neither can I ever return myself to the state in
which I can wreak limited, controlled havoc.

What I want to do is change my euid to something non-threatening, thus
preventing havoc-wreaking, and then temporarily change it back to root
from time to time when I need to be root. This is, BTW, not an
uncommon thing for an Internet-related daemon process to do (popper,
the ucb POP3 deamon does this, for instance).

It seems to me that perl should seek to do one of two things:

(1) Turn on tainting any time you are able to do privileged things. In
this case, the appropriate check for tainting (ignoring the gid issue)
would simply be
tainting |= !euid
One could argue that this is a reasonable way to work, though I suspect
all manner of perl scripts designed to run as root would be broken by
this.

(2) Turn on tainting any time you are masquerading as root, even though
you are not really root. Then my proposed code would be right:
tainting |= !uid && (uid != euid)

what is actually happening is:

(3) Turn on tainting any time you are masquerading as anyone. Thus,
tainting is turned on if you are a regular Joe masquerading as root,
but also if you are root masquerading as a regular Joe.

I think (2) is what you really want, isn't it? I mean, why should perl
care if root is masquerading as an average Joe. This is a _good_ thing,
isn't it?

What am I missing?

-Tony
Re: setuid FROM root causes tainting [ In reply to ]
Tony Camas writes:
> (1) Turn on tainting any time you are able to do privileged things. In
> this case, the appropriate check for tainting (ignoring the gid issue)
> would simply be
> tainting |= !euid
> One could argue that this is a reasonable way to work, though I suspect
> all manner of perl scripts designed to run as root would be broken by
> this.
>
> (2) Turn on tainting any time you are masquerading as root, even though
> you are not really root. Then my proposed code would be right:
> tainting |= !uid && (uid != euid)
>
> what is actually happening is:
>
> (3) Turn on tainting any time you are masquerading as anyone. Thus,
> tainting is turned on if you are a regular Joe masquerading as root,
> but also if you are root masquerading as a regular Joe.
>
> I think (2) is what you really want, isn't it? I mean, why should perl
> care if root is masquerading as an average Joe. This is a _good_ thing,
> isn't it?

I want to disagree...

alternative 4 follows

(4) Turn on tainting when somebody who is not root is masquerading as
anyone else. If plain user Joe instals a suid thing, I want him to be
protected from Bob.

Eero



--
Eero.Pajarre@vlsi.fi VLSI Solution OY
Tel:+358 31 3165270 Kanslerinkatu 6
Fax:+358 31 3165220 FIN-33720 Tampere, Finland
Re: setuid FROM root causes tainting [ In reply to ]
>>>>> "Tony" == Tony Camas <tony@bosauto.com> writes:

Tony> What am I missing?

Alternative (4), which is how the big boys do it.

Be root, but when you want to be joe for a moment:

defined $pid = fork or die "no forks (too many philosophers)";
unless ($pid) {
$< = $> = getpwnam("joe");
do_the_joe_thing;
exit 0;
}
waitpid($pid);

Highly portable. Very effective. Works on BSD and sys5 style kernels
with and without saveuid.

Name: Randal L. Schwartz / Stonehenge Consulting Services (503)777-0095
Keywords: Perl training, UNIX[tm] consulting, video production, skiing, flying
Email: <merlyn@stonehenge.com> Snail: (Call) PGP-Key: (finger merlyn@ora.com)
Web: <A HREF="http://www.teleport.com/~merlyn/">My Home Page!</A>
Quote: "I'm telling you, if I could have five lines in my .sig, I would!" -- me
Re: setuid FROM root causes tainting [ In reply to ]
Tony> What am I missing?

Alternative (4), which is how the big boys do it.

Be root, but when you want to be joe for a moment:

defined $pid = fork or die "no forks (too many philosophers)";
unless ($pid) {
$< = $> = getpwnam("joe");
do_the_joe_thing;
exit 0;
}
waitpid($pid);

Highly portable. Very effective. Works on BSD and sys5 style kernels
with and without saveuid.

sorry, doesn't work on 4.4BSD derived systems, nor does it seem to work on
svr4 systems:

pegasus ~# perl -e '$< = $> = getpwnam("mrg"); print "$>, $<\n";'
117, 0
pegasus ~# perl -e '$> = $< = getpwnam("mrg"); print "$>, $<\n";'
setruid() not implemented at -e line 1.

under netbsd:

splode ~# perl -e '$< = $> = getpwnam("mrg"); print "$>, $<\n";'
127, 0
splode ~# perl -e '$> = $< = getpwnam("mrg"); print "$>, $<\n";'
0, 0

but netbsd's setruid() doesn't _really_ do anything (it just checks
that setruid() _could_ have been called correctly with those arguments,
and returns the correct error if it would have failed -- but it doesn't
change the actual real userid, as this doesn't happen in netbsd).

it appears what i posted about $< and $> in perl 4 affects more than
just 4.4BSD systems, as i originally thought. svr4 and 4.4BSD both are
affected. funny that -- they both impliment the same non-posix functions
that don't work with perl. :-)

larry: have you thought about this at all ?

.mrg.
Re: setuid FROM root causes tainting [ In reply to ]
Excerpts from the mail message of matthew green:
) defined $pid = fork or die "no forks (too many philosophers)";
) unless ($pid) {
) $< = $> = getpwnam("joe");
) do_the_joe_thing;
) exit 0;
) }
) waitpid($pid);
)
) Highly portable. Very effective. Works on BSD and sys5 style kernels
) with and without saveuid.

Except in Perl, it seems.

) sorry, doesn't work on 4.4BSD derived systems, nor does it seem
) to work on svr4 systems:
)
) pegasus ~# perl -e '$< = $> = getpwnam("mrg"); print "$>, $<\n";'
) 117, 0
) pegasus ~# perl -e '$> = $< = getpwnam("mrg"); print "$>, $<\n";'
) setruid() not implemented at -e line 1.

Definately not "do what I mean" here.

But, on svr4 systems:

% perl -e '($u,$g)=(getpwnam("tye"))[2,3];($>,$<)=($u,$u);print "$< $>\n"'
109 109

A bit of a pain, yes.

I think this and a few other #ifdef blocks of Perl need to be
rewritten with an eye toward using POSIX first. It would also
be nice if, when a POSIX way is not available but both SysV and
BSD ways are, that they would use SysV ways on SysV systems and
BSD ways on BSD systems. This is on my to-do list but don't
expect it any time soon.
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
Re: setuid FROM root causes tainting [ In reply to ]
> No, I think that where uid == 0 and euid != 0, you should ignore
> tainting. After all, the person didn't need a perl script to do
> damage, they OWN the machine.

no. if uid is 0, you can set euid to 0, which is a problem.
you deserve tainting checks.

> To be more general, given real security (in my small world this STARTS
> with having multiple levels of authorization and privilege), taint
> would only be engaged when you were running a script that had some
> privilege that the user who RAN it did not. We're not trying to
> protect users from trojans, here, so it makes no sense to restrict a
> step-down in privilege.

i disagree.

--tom
Re: setuid FROM root causes tainting [ In reply to ]
In <9510131721.AA19602@taz.bosauto.com>
On Fri, 13 Oct 1995 17:20:26 -0400
Tony Camas <tony@bosauto.com> writes:
>
>(3) Turn on tainting any time you are masquerading as anyone. Thus,
>tainting is turned on if you are a regular Joe masquerading as root,
>but also if you are root masquerading as a regular Joe.
>
>I think (2) is what you really want, isn't it? I mean, why should perl
>care if root is masquerading as an average Joe. This is a _good_ thing,
>isn't it?
>
>What am I missing?
>
The common case of something that starts as root then sets euid to
"Joe" as a function of received data directed to "Joe".
The taint checks go on to stop "Joe" leaving tojan horses
about and using us a a way to get root access.

Now if you are just setting euid to "daemon", "uucp" or "bin" or other
pseudo-users this is a pain, but there is no easy check for
this class vs just-anyone.
Re: setuid FROM root causes tainting [ In reply to ]
: > No, I think that where uid == 0 and euid != 0, you should ignore
: > tainting. After all, the person didn't need a perl script to do
: > damage, they OWN the machine.
:
: no. if uid is 0, you can set euid to 0, which is a problem.
: you deserve tainting checks.
:
: > To be more general, given real security (in my small world this STARTS
: > with having multiple levels of authorization and privilege), taint
: > would only be engaged when you were running a script that had some
: > privilege that the user who RAN it did not. We're not trying to
: > protect users from trojans, here, so it makes no sense to restrict a
: > step-down in privilege.
:
: i disagree.

One issue here is whether you're setting euid merely to do a known
operation on behalf of another user, or to blindly run some code for
the user. Tainting assumes trusted code is running over untrustworthy
data, so in the latter case, tainting isn't enough anyway, and you
should really be setting the real uid as well as the effective uid.

In the former case, there's less reason to do tainting unless the
euid was set using tainted data, in which case you probably want to
blow the whole thing off right then and there.

On the other hand, it can be argued that a program setting the euid
is equivalent to a setuid program anyway, and should be held to the
same standard.

Another factor is that it's easy to force tainting on currently, but
harder to force it off.

I haven't come to any conclusion yet. I did install a bug report though.

Larry
Re: setuid FROM root causes tainting [ In reply to ]
> PS: Tom, just what do you disagree with?

Well, basically the assertion that tainting shouldn't
be set at certain times even when euid and uid should differ.

But I do agree that a tainted program is still not so safe
as Malcolm's safeperl extension can provide.

--tom