linuxperlprocfsspoofcmdline-args

Why is it allowed to modify argv[0]?


I have been working on a project that uses PIDs, /proc and command line analysis to validate processes on a system. My code had to be checked by the security guys who manage to break it with a single line... embarrassing!

#!/usr/bin/env perl

$0="I am running wild"; # I had no clue you can do this!

system("cat /proc/$$/cmdline");
print("\n");
system("ps -ef | grep $$");

# do bad stuff here...

My questions:

  1. I see some uses cases for the above, like hiding passwords given on the command line (also bad practice) but I see a lot more problems/issues when one can hide processes and spoof cmdline. Is there a reason it is allowed? Isn't it a system vulnerability?

  2. How can I prevent or detect this? I have looked into /proc mount options. I also know that one can use lsof to identify spoofed processes based on unexpected behavior, but this won't work in my case. At the moment I am using a simple method to detect if the cmdline contains at least one null (\0) character which assumes that at least one argument is present. In the above code, spaces need to be replaced with nulls to bypass that check which is something I couldn't find how to implement in Perl - writes up to the first \0.


Solution

  • To answer 1:

    It's because of how starting a new process actually works.

    You fork() to spawn a duplicate instance of your current process, and then you exec() to start the new thing - it replaces your current process with the 'new' process, and as a result - it has to rewrite $0.

    This is actually quite useful though when running parallel code - I do it fairly frequently when fork()ing code, because it makes it easy to spot which 'thing' is getting stuck/running hot.

    E.g.:

    use Parallel::ForkManager;
    my $manager = Parallel::ForkManager -> new ( 10 ); 
    
    foreach my $server ( @list_of_servers ) {
        $manager -> start and next;
        $0 = "$0 child: ($server)";
        #do stuff;
        $manager -> finish;
    }
    

    You can instantly see in your ps list what's going on. You'll see this sort of behaviour with many multiprocessing services like httpd.

    But it isn't a vulnerability, unless you assume it's something that it's not (as you do). No more than being able to 'mv' a binary anyway.

    Anyway, to answer 2... prevent or detect what? I mean, you can't tell what a process is doing from the command line, but you can't tell what it's doing otherwise anyway (there's plenty of ways to make a piece of code do something 'odd' behind the scenes).

    The answer is - trust your security model. Don't run untrusted code in a privileged context, and it's largely irrelevant what they call it. Sure, you could write rude messages in the process list, but it's pretty obvious who's doing it.