Monday, April 13, 2009

Episode #22: Death To Processes

Paul Says:

Ever been in the mood to just kill things? This happens to me when I use Windows. There are more interesting ways to kill things in Linux than you think, for example:

# killall top

Sometimes you want to put processes in the background. You can do this by appending "&" after the command, or hitting CTRL-Z and typing "bg" once the command has been started. But what if you try to quit the process and you are ignored? Reboot? (No, that's just if you're running Windows and this happens). You can hit CTRL-Z and then use the kill command as follows:

$ while :; do cat /dev/null; done
[1]+ Stopped cat /dev/null

The process is stopped, but it's still running:

$ ps waux | grep null
root 77241 0.0 0.0 599780 440 s005 R+ 10:28PM 0:00.00 grep null
root 77238 0.0 0.0 599700 372 s005 S 10:28PM 0:00.00 cat /dev/null

To kill the previous command that was put in the background, do the following:

$ kill %1

[1]+ Stopped cat /dev/null

Now it's not running at all:

$ ps waux | grep null
root 77243 0.0 0.0 599780 388 s005 R+ 10:28PM 0:00.00 grep null
[1]+ Terminated cat /dev/null

Now I will just wait until Hal hands something to me, usually it's something that rhymes with glass.

Hal Says:

Of course, if Paul wanted to kill the process, I'm wondering why he didn't just hit ^C instead of ^Z. Seriously, though, there's all kinds of interesting ways to kill processes in Unix. In addition to the killall command Paul's using, there's also pkill. I actually prefer pkill to killall, because it lets me do things like:

# pkill -P 1 sshd

This command means "kill all sshd processes whose parent process ID is 1", which kills only the master sshd process leaving all of the users on the system still logged in. Or I could kick Paul off the system:

# pkill -u paul

Did you know that you can use lsof to help you kill processes? Check this out:

# umount /home
umount: /home: device is busy
# kill `lsof -t /home`
# umount /home

The "-t" option to lsof tells it just to output the PIDs of the matching processes-- in this case all processes that have files open under /home. Once all of those processes are dead, you can successfully unmount the volume. Note that you're going to have some very unhappy users after this action, but if you absolutely positively have to unmount a file system for some reason...

Another point to mention is that you can kill commands via the top command. Just hit "k" in the window where you're running top and enter the PID you want to kill. This technique is useful for killing a runaway process that's eating all your CPU time. You can also use it to kill processes that are eating tons of memory: hit "O" to pick a different sorting criteria and select "q" to sort by Resident Size. Now you'll see the processes sorted by the "RES" column and it will be easy to pick out and kill the ones eating lots of memory.

Ed Steps up to the Plate:
Killing processes in Windows? Man, we have a lot of options. One of my favorite ways is to use wmic, God's gift to Windows. While you can manipulate many (most?) aspects of Windows using WMIC, here, we'll use it to kill processes by running:

C:\> wmic process where [where_clause] delete
It's the where_clause where we have some real power in fine tuning what we want to kill. To kill a process based on its name (like Paul's killall above), we can run:

C:\> wmic process where name="calc.exe" delete

Here, I've just killed any process named calc.exe, the little Windows calculator.

Would you rather kill something based on its pid number? You could run:

C:\> wmic process where processid="536" delete

You can construct where clauses around all kinds of process attributes, including executablepath, parentprocessid, or even commandline options. To see the attributes exposed via wmic process, run:
C:\> wmic process get /?

You can even write where clauses to match multiple attributes using an "and", putting in some parentheses where appropriate. To mimic Hal's fu about killing a process named sshd with a parent processid of 1, we could run:

C:\> wmic process where (name="sshd" and parentprocessid="1") delete

Of course, on a real Windows box, you likely won't use that specific name and parentprocessid, but you get the idea and can easily adapt it.

In addition to "and", note that "or" is also supported. Plus, you can do substring matching with where clauses that include "like" and "%", as follows:

C:\> wmic process where (name like "%bot.exe") delete
That'll kill any process with a name that ends with bot.exe.

But, there's one important attribute missing from wmic process: the user name! Doh! Thanks for nothing, Microsoft.

But, sometimes you really want to kill all processes running as a given user... Paul sometimes can be a bother when he logs onto a machine, after all. For this, we can rely on the taskkill command. That command allows us to kill processes based on all kinds of things, including processid (specified with /PID [N]) or process name (specificed with /IM [name]). But, taskkill gets really useful with its filtering rules, specified with /FI "[filter]". Let's kill all processes running as user paul:

C:\> taskkill /F /FI "username eq paul"
The /F means to forcefully terminate a process. The taskkill filtering language is very flexible, supporting wildcard strings of *, and offering options for eq (equals), ne (not equals), gt, lt, ge, le for a variety of process attributes. Various attributes we can filter on include status (running or not running), memusage (if you're a memory hog, I'll kill ya!), username (you'd better behave, Paul), modules (if a process has loaded metsrv.dll, the Metasploit Meterpreter, I can kill it! Oh, and if it's a critical system process, I just hosed my machine), services (kill the process inside which a given service runs), and even windowtitle. That's a lot of precision, letting you target your process kills.

Specific filtering syntax is available by running:
C:\> taskkill /?