Cover V01, I04
Article
Figure 1
Listing 1

nov92.tar


sukill: Stopping Unruly Processes

Steven G. Isaacson

A runaway process on a small system isn't much of a problem: it's easy enough to identify the guilty process and its owner and have either the owner or a user with the root password "fix" the problem.

On a large system with dozens or hundreds of users, a more formal approach is required. In this case, what's needed is a tool that allows an ordinary user to kill another user's process without compromising system security.

The kill Command

Processes can be stopped with the kill command.

kill [ -signal ] pid ...

The kill command sends a signal to the specified process-id (you determine the correct process-id using the ps command).

Many different signals may be sent to a process -- the hangup signal, interrupt, quit, exceeded CPU time limit, floating point exception, kill, bus error, segmentation violation, user-defined signal, death of a child -- but the two signals most commonly sent are: software termination (signal 15) and kill (signal 9). These two are defined in /usr/include/sys/signal.h as SIGTERM and SIGKILL.

SIGTERM is the default signal sent by kill. It provides a warning that can be caught by the process and thus be dealt with or ignored. vi, for example, catches the signal and then cleans up its temporary files before exiting.

SIGKILL, however, cannot be caught or ignored. It terminates the process immediately.

The problem with the kill command is that it requires super user provileges to kill a process other than your own. To make it generally available, you could choose to create a set-uid root copy of the command (i.e., /bin/kill).

A set-uid program temporarily changes the effective user id of whoever is running the program. If the user id is set to root, any user who runs the program has root privileges.

Thus if you make kill a set-uid root program, the user will temporarily acquire root privileges and will be able to kill any process on the system.

Set-uid programs are potentially dangerous, however, and should generally be avoided. In the case of the kill command, any user may kill any other user's process and no one would be the wiser; moreover, any user (when running as root) could bring down the system by killing pid -1.

sukill provides a better way to stop unruly processes.

sukill [ -signal ] pid ...

sukill is similar to the kill command except that it allows you to kill processes other than your own. It does not, however, automatically give every user on the system the power to kill.

sukill Safeguards

sukill has three safeguards: it restricts the range of the process-ids that can be killed; it can be used with "allow" and "deny" files; and it logs an audit trail.

Restricted PIDs

sukill does not allow you to kill a process-id less than 100. This prevents users from inadvertently (or intentionally) bringing down the system, which could happen if they're allowed to kill system processes.

One hundred is a happy medium between the system processes that are started at boot time -- for example, init, sendmail, and cron -- and user processes. The ability to kill system processes should be left to the system administrator. If this value is too high or too low, you can easily change it.

Allow and Deny

sukill can be used with "allow" and "deny" files. These are files that contain a list of users who are allowed or denied access to sukill.

To permit specific users to run sukill, add their lognames to the sukill.allow file. To deny particular users, add their lognames to sukill.deny.

If neither sukill.allow nor sukill.deny exists, then every user has permission to execute sukill. If you do use these files, set their permissions so that only root can write to them.

In practice the allow and deny files are seldom used, mainly because of sukill's verbose logging. However, different sites have different requirements, and you may find that allow and deny files are appropriate.

Logging

sukill writes the following information to the log file: logname, sukill command-line arguments (the optional signal level and the pid(s) to be killed); system date and time; logname (again), user id, group id, effective user id (always 0 unless sukill is not installed correctly), effective group id, current user id name, current working directory, values of $HOME and $NAME environment variables; and finally the results of a verbose listing from /bin/ps for the specified pid(s).

The output from /bin/ps is exactly what you would expect a "reasonable user" to look at before killing someone else's process. In fact you must use the ps command to obtain the pid number. Figure 1 shows a sample logfile entry.

The entry reveals that a process owned by sneed was killed by jamesy and that jamesy used -9, the SIGKILL signal. The file also shows that the process that was killed had no controlling tty and had been going for three hours and two minutes.

The log file is not pretty and is seldom examined, but if a problem does occur -- a user's program keeps stopping unexpectedly, say -- it provides an audit trail.

Source Code

Listing 1 contains all of the source for sukill. Simply compile it, change the owner to root, and change the permissions to 4755. The logging section may have to be customized for your system. It could be made less verbose or could perhaps have installation-specific requirements added to it.

sukill is a simple and safe way to give more power to the user. You may even find that you use it yourself instead of always having to su to root in order to kill a process.

About the Author

Steven G. Isaacson has been writing C and Informix 4GL applications since 1985. He is currently developing automated testing tools for FourGen Software, the leading developer of accounting software and CASE Tools for the UNIX market. He may be reached via email at uunet!4gen!steve1 or steve1%4gen@uunet.uu.net.