Cover V03, I06
Article
Figure 1
Listing 1
Listing 2
Listing 3
Listing 4
Sidebar 1

nov94.tar


suFirewall: Creating a Controlled Setuid Environment

Chris Cox

People who are new to UNIX but are familiar with different operating systems (e.g., VMS, MVS, etc.) typically find UNIX more "open," but inherently non-secure. Their opinion is often based upon their understanding of how controlled (or more likely, restricted) their previous OS was in comparison to UNIX. I suggest that UNIX should not be seen as a non-secure environment, but rather a highly tailorable environment that allows system administrators to construct their own security mechanisms, protocols, and methodologies. What I have detailed here is a very flexible tool to aid in defining security within your UNIX environment.

The key to UNIX's "openness" and/or "closedness" lies within its files. To control UNIX you need to control files. Arguably the most influential file type within UNIX is the directory (this differs from other OSs, which usually give equal if not higher precedence to the files within a directory). In UNIX, if I have read (r) and search (x) permissions for a directory, I will be able to read all readable files, copy them -- at the very least obtain a directory listing of the file names therein. However, if I have write (w) permission via user, group, or other, then I can change file ownerships and do file removals -- even if neither the directory nor the file belongs to me. Ultimately, if you do not want people to manipulate or even look at the contents of a directory you own, you should remove all permissions for group and other within the directory mode (e.g., 700 or rwx------). But this would seem to be going from one extreme, very "open", to another, very "closed"; typically, a UNIX security policy falls between the two extremes.

setuid programs allow certain operations to be performed as a different user within the controlled environment of the program. In the "good old days" of UNIX, even scripts were allowed to be setuid. But since the PATH environment variable is usually dynamic, setuid programs create a potential security loophole: they can be used to exploit and/or violate the privileges of the effective user ID if PATH is reset so that executables within the script would point to executables on the overriding PATH. The now ancient solution to this problem was to fully qualify the executable path names within the setuid script. This was an ugly solution in that it depended upon the discipline of the programmer to assure that directly and indirectly called executables had fully qualified path names. Most UNIX systems do not allow setuid scripts anymore (DGUX 4.x was the last one I knew of). However, since UNIX shell script is an excellent rapid prototyping language, this has made it more difficult to build powerful setuid applications in a short period of time.

A helpful UNIX utility would be a sort of "firewall" for setuid program execution -- including scripts. One example of an application where this suFirewall could be used is with source code control. By using setuid front ends to the source code control commands in SCCS, you could hide the actual s-files from the user. Other examples may include giving restricted access to root level commands or the setting up of a secured login environment for restricted user accounts.

What I describe here is a secure process for creating setuid programs -- scripts or binary executables. This process should work for any SVR4 UNIX as well as most UNIX derivatives which support symbolic links.

Making Directory and File Structures

Two directories (at least) are necessary to the secured execution environment. The first directory, the Secured Directory, contains the executable files where only the effective user has access. The second directory, the Public Directory, contains the suFirewall program as well as the interface stubs which determine what Secured Directory commands may be executed.

Create the Secured Directory with the owner set to the effective user id you wish to exploit (e.g., suser). Set the permissions on the directory to 700, so that only the owner can examine or make changes to files contained there. Within this directory, place all of the executables that need to execute as the effective user as well as any other files referenced by the executables (e.g., configuration files). Do not set the setuid bit on the executables: suFirewall will do this.

To force even the owner of the Secured Directory to use the suFirewall access interface, you may want to optionally prefix or suffix the executables with a string of your own choosing. This will prevent accidental bypassing of the suFirewall interface (for instance, when dot (.) has precedence in your PATH). The suFirewall access interface will use the name of the stub file found within the Public Directory and will create the name of the actual secured executable by prefixing or suffixing your special character string. You can use non-printable characters for your prefix or suffix; I prefer this, since it makes it even more difficult to accidentally invoke the Secured executable name.

The Public Directory (e.g., /usr/local/bin) will have permissions such that all users of the suFirewall interface can execute the "stub" files located there. Each "stub" file is a symbolic link to the suFirewall program. The "stub" file name is the name of the Secured Directory executable without the optional suffix or prefix. The suFirewall program can reside here, but if users have write permission to the Public Directory (thus the ability to delete/replace the suFirewall), you might prefer to place it in a directory that doesn't allow general write access. In addition, suFirewall itself may only have execute permission for members of a particular UNIX group. Figure 1 shows how the resulting directory structure might look.

Making the suFirewall Program

As mentioned earlier, all the "stub" files are symbolic links to the suFirewall. The actual suFirewall executable uses the basename of argv[0] plus any optional prefix or suffix characters (known only to suFirewall) to determine which program in the Secured Directory to execute.

All of the executable programs and scripts are funneled through this setuid executable (suFirewall will do an execvp, among other things). Listing 1 shows full source for this suFirewall program. Below are the general steps to follow in coding the program:

1. Reset the PATH to the standard path for the platform.

2. Prepend to this PATH the path(s) where your secured programs and scripts will reside. Use putenv to modify PATH in the environment.

3. Take the basename of argv[0] as the name of the secured program desired. Optionally, prefix or suffix printable/non-printable characters to the newly formed Secured Directory program name. I'll refer to the resulting program name as secured_name.

4. Use putenv to place anything else you want into the environment.

5. Perform an execvp(secured_name, argv).

6. Compile the program and turn on the setuid bit for the effective user.

7. Place the program in a directory area which is searchable by and is on the PATH of the users of the Secured programs.

Drawing "Effective" Conclusions

Since the suFirewall actually controls the user's environment, the user cannot simply alter his/her PATH to circumvent security. Also, the user is completely isolated from the source and executables used by the suFirewall, to the extent that he/she does not know if a binary or a script is really being executed.

Doing a ps while a secured shell script program is running will show the shell being invoked with the secured_name as its first argument. If you find this too revealing, then you could execvp a shell directly with argv[0] set to whatever name you want in order to better hide the fact that you are using a shell script. This strategy, however, incurs the undue overhead of invoking a shell to execute binary files.

You could also put an executable in the Secured Directory which maps to the name of the suFirewall program itself. This program could be used to perform real work.

Getting Realuid

Sometimes within a setuid program, you will need to revert back to your real user id. For example, your own file permissions may be such that you cannot access the files under another user id (this is especially true for AIX users, see the sidebar "AIXceptions").

Within a C program, reverting to the real user id is a trivial call to setuid. Doing the same from a script, however, requires using a separate program. Call the program realdo from inside your secured scripts to execute commands as the real user instead of as the effective user. Listing 2 shows realdo.c.

Applying suFirewall

As I mentioned earlier, source code control is an excellent proving ground for suFirewall. Normally in SCCS, the s-files (delta files) are read accessible (mode 444) and found in a searchable directory (mode 755). This means that only the SCCS toolset can manipluate the s-files and only the owner of the s-files can use administrative commands. However, if you have customized the way files are manipulated by writing scripts around the standard SCCS commands, might not want people to access the s-files via the normal SCCS commands.

One solution is to make the directory for the s-files accessible only by the effective user (e.g., suser) of suFirewall. This way, only the suFirewall command set can manipulate the files. The effective user can still do the SCCS commands (since he/she owns the s-files), but this is generally acceptable.

I also mentioned earlier the possibility of using configuration files within the suFirewall commands. You could for instance, source in a file of local/environment variables that could be used within the suFirewall scripts to locate the s-file area, perform extra security measures, or define commonly used functions across all suFirewall scripts.

Listing 3 contains the source for a script which will do a get -e (check out) of a file. Listing 4 sets some variables to enable you to locate where the s-files reside, what release trunks are locked down, and some shell functions.

Afterthoughts

UNIX can be a very secure operating environment as long as you know the secrets of security. Avoiding setuid scripts is too limiting a solution to setuid "backdoors." I hope that suFirewall will help you to perform rapid prototyping, if not full-scale development, using UNIX scripts.

About the Author

Chris Cox is a Computer Science graduate of Texas A&M University with an Electrical Engineering minor. He has been working with UNIX since System III, and over the past ten years has been a software developer, configuration manager, porting engineer, and system administrator for heterogeneous UNIX environments. Chris is currently employed as a configuration manager by CARE Systems Corporation, Dallas, TX. He can be reached via email at Chris_Cox@ps.net.