develooper Front page | perl.perl5.porters | Postings from April 2008

Re: Taint (PL_tainting, SvTAINTED_on, SvTAINTED_off, SvTAINT)

Thread Previous | Thread Next
Nicholas Clark
April 29, 2008 09:15
Re: Taint (PL_tainting, SvTAINTED_on, SvTAINTED_off, SvTAINT)
Message ID:
On Tue, Apr 29, 2008 at 12:03:40PM +1000, Paul Fenwick wrote:

> [snippage of things with which I agree]

[me too. Well. more stuff that I don't disagree with. I'm actually in two
minds about much of this]

> When taint can be switched on part-way through our program, we *don't know* 
> what an untainted piece of data means.  It could have undergone careful 
> scrutiny, or it could be some complete garbage that never got tainted.  We 
> just don't know.

[except that one, which seems important to me]

> But that's not what we're doing.  If we're fully dropping privileges by 
> changing both our RUID and EUID, then late-acting taint doesn't activate. 
> If we're RUID root, and (temporarily) drop our EUID to another user, then 
> late-acting taint doesn't activate either.
> It's *only* in the rather odd situation that we didn't start in taint mode, 
> have changed our RUID to a non-root user, and our EUID (or EGID) doesn't 
> match that late-acting taint comes into effect.

I don't think that you're right here, but testing wise, OS X sucks:

# perl -le '$< = 1; print ${^TAINT}'
setruid() not implemented at -e line 1.

and the various other machines that I have root access on are powered down and
without network.

Anyway, by inspection of the code, I thought that some of your details are not
correct. The C code is always

	PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));

so it never turns tainting off.

If a Perl script changes its RUID and EUID it can't do it in one hit. It would
have to write something like

  $< = $> = $id;

$ perl -MO=Concise,-exec -e '$< = $> = $id;'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v
3  <$> gvsv(*id) s
4  <$> gvsv(*>) s
5  <2> sassign sKS/2
6  <$> gvsv(*<) s
7  <2> sassign vKS/2
8  <@> leave[1 ref] vKP/REFC
-e syntax OK

But then I tried to test it, and I could set both IDs (there's an OS X hack in
the C source for just that) and no tainting...

There's a bug even in the implementation as intended, I feel. If you set the
EUID first, then the RUID (PL_uid) is still 0, so the expression is 0, and
PL_tainting is unchanged.

	PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
                        D'oh!  meh

Then when you set the RUID to the EUID, even though PL_uid is non-zero, the
?UIDs are now equal, so PL_tainting is still unchanged

	PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
                        woohoo!            D'oh!     ...        D'oh!

(this joke fails because I can't work out what Simpsons phrase to use for
short-circuiting or)

> Since that's such an odd thing to do[1], I can *kind of* see this as a way 
> of saying "we don't want to trust things now".  However I think it's an 
> obscure and unexpected way of doing so, and not worth the loss of the 
> assurances that we'd otherwise be able to expect if we see ${^TAINT} 
> enabled.

Yes, I could see another view, whereby there would be two variables, one for
late acting taint, and one for "it was always tainted", and no Ministry of
Truth capable of setting the second, but I can't see a good way to do this
and preserve some level of backwards semantic sanity.

Mmm, except maybe having ${^TAINT} as undef with no tainting, true with real
tainting, and 0 (defined but not true) with late acting taint.

> I'd love for late-acting taint to be considered deprecated, and will 
> cheerfully write a patch and tests if we reach this consensus.

But this sounds more simple.

Nicholas Clark

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About