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

Hello Wise Monks,

Is it possible to configure my linux server such that a user can be allowed to execute a perl program, but not read the code? Can this be done by setting permissions? If not, how can I accomplish this?

Thanks a lot in advance.

Gorby

Replies are listed 'Best First'.
Re: Execute But Not Read
by Thilosophy (Curate) on Jan 21, 2005 at 06:15 UTC
Re: Execute But Not Read
by mhearse (Chaplain) on Jan 21, 2005 at 03:50 UTC
    I think the Perl interpreter needs to be able to read the contents of the file, so chmod 711 won't work for programs interpreted at run-time. You could go suid, chmod 4111, but that is ALL to dangerous. A safer solution would be something like Solaris RBAC (Role Based Access Control), or BSD MAC (Mandatory Access Control).
      You could go suid, chmod 4111, but that is ALL to dangerous.
      Well you cannot execute a script on either FreeBSD or Linux that has the SUID bit set ..

      OK, you still end up with an SUID program, but what about putting the real Perl script in a directory that users cannot read, then calling it with this wrapper:
      /* wrapper.c */ #define REAL_PATH "/usr/local/bin/secret/secret.pl" main(ac, av) char **av; { execv(REAL_PATH, av); }

      Compile it:  cc -o secret wrapper.c

      Put the real script in the unreadable directory:
      # mkdir /usr/local/bin/secret # cp secret.pl /usr/local/bin/secret/ # chmod -R 0711 /usr/local/bin/secret/

      Make the wrapper you just compiled SUID root:
      # chown root:root secret # chmod 4711 secret

      A unprivileged user should be able to execute the "secret" program, but not read the real Perl code.. so how dangerous would it be to have this suid program around? Maybe in the Perl script you could make sure no arguments are passed in as a first level precaution.. ? I know, it's a Bad Thing.

      You could also just compile the perl script into an executable with perlcc - I don't believe you can see the source code.

        you don't have to use the big gun (root user) to hide the script from 'normal' users. just create an extra user (with no extra privileges) and chown/chmod the directory/script to him.
        ~/runnables> su Password: tmodel# uname FreeBSD tmodel# chown root:wheel test.pl tmodel# chmod 4711 test.pl tmodel# exit exit ~/runnables> more test.pl test.pl: Permission denied ~/runnables> ./test.pl At 6:00 AM, Seatac Airport, WA conditions were cloudy skies at 52&deg +;F,wind was east at 5 mph. The relative humidity was 97%, and barom +etric pressure was falling from 30.05 in.
        But using Access Control is safest.
Re: Execute But Not Read
by Pearte (Beadle) on Jan 21, 2005 at 07:12 UTC
    Perl is an interpereted, scripting language. This means the source is read at runtime. Though you could change the permissions according to what you describe, it would be useless as the commands that a script contains need to be read by the interpereter in order to run.

    Theoretically, one can compile perl into a binary modules that are then (usually) called by other scripts or c programs. The code in the module is no longer human readable (what they call byte-compiled), and that may be good enough for what you're after.

    Honestly though, I, for one, have never done this. There are references on this site for it though. Checkout this post.
Re: Execute But Not Read
by monkfan (Curate) on Jan 21, 2005 at 03:40 UTC
    Hi,

    You can always change mode by taking away "read". with these commands:
    chmod =r yourcode.pl OR chmod 444 yourcode.pl OR chmod a-wx,a+r yourcode.pl
    If that's not what you want you probably want to put the password into your perl code and read this file into your perl code.

    But why you want to hide your code? Usually the rule is "hide the data but open the code". If you hide the code, your program isn't safe.

    Regards,
    Edward WIJAYA
        That works fine on OpenBSD. Even a perl script, like this: ---x--x--x 1 root wheel 33 Jan 21 10:13 hello.pl can be executed by non-root user. But it has to be called directly, like: ./hello.pl Trying to run it with "perl hello.pl" will give permission denied... Advanced users will still be able to access the source with ktrace or ptrace though. But if you own the server, you could always hack your kernel to not allow tracing root-owned programs. And the users won't be able to copy your program to run elsewhere since the perms don't allow it...
Re: Execute But Not Read
by Anonymous Monk on Jan 21, 2005 at 14:10 UTC
    Take away their monitors, but not their keyboards!
Re: Execute But Not Read
by mkirank (Chaplain) on Jan 21, 2005 at 10:05 UTC

    Use perlcc and compile the script
Re: Execute But Not Read
by jbrugger (Parson) on Jan 21, 2005 at 10:08 UTC
    hi, You could use an obfuscator (there are some good commercial ones, try google), but i don't see the point.
    Either is the source so bad you don't want anyone to see it? or are you scared that someone steals it?
    If someone can read the code, probably someone can write it as well.
    If you see an an application, you can probably build your own version. I don't see any point in hiding code other than hiding your mistakes from the world.
Re: Execute But Not Read
by rir (Vicar) on Jan 21, 2005 at 14:42 UTC
    I think yes. Check out the binfmt_misc stuff.

    I have a quick implementation of a hash/bang/bang (hbb) script invocation system using this mechanism. The idea of this was that:

    #!! perl ...
    would look in system defined locations rather than an user's path. If root was the user a differing set of locations could be used.

    If you fiddle with permissions and this mechanism I'm sure you could do what you want. This would be in C.

    The binfmt_misc stuff is very clean and simple to handle. You may have hbb to give you a kickstart.

    Be well,
    rir

Re: Execute But Not Read
by ambrus (Abbot) on Jan 21, 2005 at 14:53 UTC

    Yes, here's a simple way.

    Give no rights to the script source to the world, only to root. Create a C program that is setuid root, and execs perl with the script as an argument. Finally, make the script start by throwing away its root privilages.

    Update: you need root so that the script can throw away its setuidity completely.

use Acme::Bleach
by frostman (Beadle) on Jan 21, 2005 at 17:58 UTC

    Hello Gorby.

    I'm sure you have some legitimate reason to hide the Perl code from your users.

    If I were in your shoes, I'd use Acme::Bleach.

    This is a fun (ie, presumably half-joking) way to make your script invisible. I suppose a real Perl guru could still find a way to un-bleach it, but that might be hard.

    Here's how it works:

    frost@penitente% cat foo.pl
    #!/usr/bin/perl
    
    use strict;
    use Acme::Bleach; 
    
    print "Eyes only, sucka!\n";
    
    frost@penitente% ./foo.pl
    frost@penitente% perl foo.pl
    Eyes only, sucka!
    frost@penitente% cat foo.pl
    use Acme::Bleach;
    
     ... many lines of whitespace here ... 
    
    frost@penitente%
    

    You have to re-add #!/usr/bin/perl on the first line (above use Acme::Bleach;) if you want to execute it directly.

    You also want very much to keep a backup copy of the code somewhere safe, and be sure to not use Acme::Bleach in that copy.

    This may not be as practical as some of the other suggestions, but it is likely to be more fun.

      I suppose a real Perl guru could still find a way to un-bleach it, but that might be hard.

      The code to 'un-bleach' is right in the ACME::Bleach module. It has to be, since perl understands Perl, not Bleach.

      --Solo

      --
      You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.
Re: Execute But Not Read
by nobull (Friar) on Jan 21, 2005 at 18:13 UTC
    If you have sperl installed and change the #! line to use sperl then you should be able to execute an execute only script.

    Unfortunately sperl needless checks to see if the script really is either suid or sgid and complains if it is not. Gee I hate over-validation.

    You can work-round this by making the script sgid to some innocuous group.

Re: Execute But Not Read -- CGI maybe?
by Dr. Mu (Hermit) on Jan 22, 2005 at 05:38 UTC
    If the programs are adaptable in such a way, you could set them up to run as cgi scripts under Apache. In a typical Apache setup, cgi scripts can be executed but are not visible to the outside world. Of course, other ways of accessing the server (e.g. ftp, ssh, etc.) will have to managed to exclude the unwanted from the cgi directory.
Re: Execute But Not Read
by itub (Priest) on Jan 22, 2005 at 05:25 UTC
    I see that several posters already gave arguments about possible bad reasons for trying to hide the code. The original poster doesn't say what the reason for wanting to hide the code is, but I'd like to add that there's very often a reason for wanting to hide the code that has nothing to do with selling the program and/or wanting to hide how it works.

    When you are using shared CGI hosting and use a database, you need to put your password in the program code or in a file that is readable by the process. If the server does not use suexec or a similar mechanism, you are in trouble unless you can find a way of allowing execution without reading, which is exactly what the OP is asking.

    I'm glad to hear that BSD has that feature, but from what I've seen, Linux doesn't. You can add a wrapper (which is what suexec does), but you have to be really careful to ensure that it is done securely.