Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Insecure dependency in open

by argv (Pilgrim)
on Jan 21, 2007 at 20:38 UTC ( [id://595809]=perlquestion: print w/replies, xml ) Need Help??

argv has asked for the wisdom of the Perl Monks concerning the following question:

I'm running a program that's sgid, and it has a command-line interpreter from which I can execute unix commands. I wrote a perl script to modify data in a private file that I own so I can run it from inside this program. It works fine outside of the sgid program, but inside, the perl generates the error,

Insecure dependency in open while running with -T switch at filename line 152.

(Line 152 is the line that opens the data file for writing, and I am not running with the -T switch.) Anticipating the taintedness of the open call (from the perl reference), I have the following in the program:

use English; $EGID = $GID; $EUID = $UID;

But, it still gives me the error. What am I missing?

Replies are listed 'Best First'.
Re: Insecure dependency in open
by shmem (Chancellor) on Jan 21, 2007 at 21:45 UTC

    Great. perl is just doing what it ought to do :-) You are not running -T, but there's a discrepancy between UID and EUID.

    The assignment is the other way round. Set the real UID to the effective UID:

    $UID = $EUID; # or $< = $>;

    Apart from that, you are perhaps missing some caveats from perlvar (emphasis added):

    $REAL_USER_ID
    $UID
    $<
    The real uid of this process. (Mnemonic: it's the uid you came from, if you're running setuid.) You can change both the real uid and the effective uid at the same time by using POSIX::setuid(). Since changes to $< require a system call, check $! after a change attempt to detect any possible errors.
    $EFFECTIVE_USER_ID
    $EUID
    $>
    The effective uid of this process. Example:
    $< = $>; # set real to effective uid ($<,$>) = ($>,$<); # swap real and effective uid
    You can change both the effective uid and the real uid at the same time by using POSIX::setuid(). Changes to $> require a check to $! to detect any possible errors after an attempted change.

    (Mnemonic: it's the uid you went to, if you're running setuid.) $< and $> can be swapped only on machines supporting setreuid().

    but why not just untaint and make your open call safe?

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      I see my "reputation" points are going into the negative whenever I reply to postings with mere reports that the advice I'm being given isn't working. Am I doing something anti-social? :-)

      Anyway, here's some new info that obviously answers the question, although I'm not sure why... leading me to think there's either a design error, or a bug.

      Turns out, the file I'm writing to is a symlink owned by root, but it points to one of my files owned by me. I wasn't aware of this till now, and is probably the result of a system restore that was recently done due to a failed hard drive. (The symlink was always there, and used to be owned by me before the crash, but it must have gotten the root ownership when it was restored.)

      It's clear that perl is noticing that the file isn't owned by me, and is preventing me from opening it without even trying. I did the right thing--I changed my gid back to my own, but perl still insists on not even attempting to open it. Why not, at this point, just defer to the OS and let open succeed or fail accordingly. Why should perl attempt to to play God (above the OS), especially if I'm trying to tell it not to. Not only did I NOT use -T, but I'm also trying my best to satisfy perl by setting my uid and gid to ME. What more do the designers of perl expect of me? If perl is going to play nazi above the OS, at least be smart about it and look to see if the final destination file is owned by me.

        I've reread the postings till now twice, but I haven't seen one important bit mentioned yet. You have repeatedly said you didn't set -T and that you have also played with trying to 'matchup' the $EUID $UID values to 'satisfy' Perl. But... it doesn't work that way.

        You have obviously read the perldiag section:

        The tainting mechanism is turned on when you're running setuid or setgid, or when you specify -T to turn it on explicitly.

        However I don't think you understood the timing. When perl starts it notices the mismatch in uid/gid values and at that point turns on taint mode. And barring magic, taint mode stays on from the start of the program onwards. You can't turn off taint mode just by un-mismatching the uid/gid values.

        Start a perl program in setuid mode and you get taint mode for free. You didn't have to ask for it, but perl wants to protect you from yourself. This only sank in the most recent time I did it to myself. So then I went off and did the untainting manipulations needed to 'clean' the data, because the program _might_ be run in taint mode, depending on the conditions when starting it.

        I see my "reputation" points are going into the negative whenever I reply to postings with mere reports that the advice I'm being given isn't working. Am I doing something anti-social? :-)

        Of course not, since what you write has nothing to do with social issues. And it's not your reputation that decreases, but the node's, even if that might involve loss of XP to you (which really isn't diminishing your reputation either :-).It's a sad fact that downvotes generally aren't accompanied by an explanation. I would like to see stated within the monastery guidelines that downvoting should be accompanied by a node or a private /msg to the author of the downvoted node, whenever possible.

        It lies in the nature of approval and dissent, that approval is rarely questioned, but dissent is. If downvoting is a corrective, and meant to incite the poster of the downvoted node to rethink the contents of their post, I deem it a good practice to give the OP a hint of what is deeemed wrong with their post.

        Back to the issue at hand: the overall picture is still not clear to me. You have a setuid binary that allows you to invoke perl with some file as argument. What beast is that binary? is it some shell? what permission bits are set for that binary, what bits are set for the perl file, or the link that points to it? what's in the perl script being invoked? What OS do you have, which perl version?

        I can't reproduce the problem with the information at hand. Or maybe I'm just not trying hard enough.

        --shmem

        update: strike through

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        leading me to think there's either a design error, or a bug
        "Ah yes, and you are the first person to have noticed this bug since 1987. Sure."
      It's the other way round. Set the real UID to the effective UID:

      Either way, I still get exactly the same error. I find it odd that nothing effects this. I also added an if statement to print an error if setting the gid fails, and it doesn't.

      You also didn't address the question on why it says "...while running with -T switch," even though I'm not. Actually, you said that because gid and egid are different, it's automatically turning it on. But, I intentionally have this option off. Shouldn't I be the one in control here? :-} So, why is it complaining?

        In your OP you wrote
        I'm running a program that's sgid, and it has a command-line interpreter from which I can execute unix commands.

        Maybe you should set $UID = $EUID in that program?

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Insecure dependency in open
by sgifford (Prior) on Jan 22, 2007 at 02:47 UTC
    Probably one of the components of the filename passed as an argument to open is tainted. Untaint it (carefully) and it should work; if it doesn't, post your open statement, and the statements that assigned to any variables that are used in the open string. Or better yet, create a minimal test case, which will probably help you in figuring out what's going on. You can use Scalar::Util::tainted to see what's getting tainted, and you should probably also read perlsec to understand what rules Perl enforces when running in taint mode.

    As others have mentioned, Perl automatically runs in taint mode when it is setuid or setgid. That is almost always the right thing to do, but if you don't like it, you can always recompile your copy of Perl with that code commented out. You could also blindly untaint all of your data, run your program under sudo instead of making it setgid, or write a wrapper program which sets up the GIDs then exec's a copy of the real program, which if you're careful will not be running in taint mode.

      well, after a lot of tests of different conditions, there are many permutations that have unearthed themselves that I wasn't aware of. Namely, using the Scalar::Util suggestion from sgifford, it turns out that the filename used was derived from an environment variable, which caused the taint. The fact that it was a symlink owned by root turns out to have been a red herring, and irrelevant to the problem. I can't say I'd have figured this out without having used the tainted() function from the Util package.

      Now that all the sleuthing has been done to determine exactly "why" the filename was tainted, I can program around it accordingly. I'm still feeling residual commitment to my statement that perl needs some programmatic way around this sort of thing, but I'm not exactly sure what that would look like... In principle, I like having the protection for basic stuff, but I also want all that rope to hang myself, should I choose to do so. :-|

        This is when taint mode is at its most useful: you didn't realize that the security of your program depended in part on an environment variable, Perl noticed that it did, and stopped the program before it did something that might be dangerous. It forced you to find the dependency, think about whether it's a real security problem or not, and then deal with it appropriately.

        If there had been an easy way to turn off taint mode, you most likely would have turned it off based on your faulty assumptions about the problem coming from symlink ownership. Instead, you found a possible bug you didn't know about, and probably made your program more secure.

        And the world is safe again. TaintMode++.

        A wise man once said you can find the rope if you RTFM.
Re: Insecure dependency in open
by Anonymous Monk on Jan 22, 2007 at 02:45 UTC
    But, it still gives me the error. What am I missing?
    Have you read perlsec?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://595809]
Approved by Corion
Front-paged by andyford
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2024-03-28 19:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found