Minimizing the Risk for Software Attack under Linux Platforms


One of the best strategies for making a program secure against attempts to exploit their privileges is to make the parts of a program that can be attacked as simple as possible. While this strategy can be difficult to employ for network programs and system daemons, programs that must be run with special permissions (via the setuid or setgid bits, or run by the root user) can usually use a few common mechanisms to limit their areas of vulnerability.

Giving Up Permissions

Many programs that need special privileges use those privileges only at startup time. For example, many networking daemons need to be run by the root user so they can listen() on a reserved port, but they do not need any special permissions after that. Most web servers use this technique to limit their exposure to attack by switching to a different user (normally a user called nobody or apache) right after they open TCP/IP port 80. While the server may still be subject to remote exploits, at least those exploits will no longer give the attacker access to a process running as root. Network clients who need reserved ports, such as rsh, can employ a similar strategy. They are run as setuid to root, which allows them to open the proper port. Once the port is open, there is no longer any need for root privileges, so they can drop those special abilities.

One or more of setuid(), setgid(), and setgroups() need to be used to reset the processes permissions. This technique is effective only if the real, effective, file system, and saved uids (or gids) are all set to their proper values. If the program is running setuid (or setgid), the process probably wants to set those uids to its saved uid. System daemons that are changing to a different user after being run by root need to change their user and group ids, and should also clear their supplemental group list.

Getting a Helping Hand

If a program needs special permissions during more than just its initial startup, helper programs may provide a good solution. Rather than making the entire application run with elevated privileges, the main program runs as the normal user who invoked it, and runs another, very small program that has the proper credentials to perform the task that requires them. By architecting the application in this way, the complexity of the code that can be attacked is dramatically reduced. This reduction makes the code much easier to get correct and to audit for any mistakes. If there are problems in the main application that allow the user to perform arbitrary actions, those actions can be performed only with the user's normal credentials, rendering any attack useful only against that user, not the user with elevated capabilities.

Using small helper programs in this way has become quite popular in the Linux community. The utempter library uses a setgid helper program to update the utmp database. The helper is very careful to validate its command-line arguments and to ensure that the application calling it is allowed to update the utmp database. By providing this service through a helper application, programs that use utempter do not need to have any special permissions themselves; before this library was written, any program that used pseudo ttys needed to be setgid to the group that owned the utmp database.

Another example of a helper program is the unix_chkpwd program used by PAM (PAM, or Pluggable Authentication Modules). Passwords on most Linux systems are stored in a file that is readable only by the root user; this prevents dictionary attacks on the users' encrypted passwords.Some programs want to make sure the person currently at the computer is the one who is logged in (xscreensaver, which can be used to lock a system's screen until the user returns, is a common program that does this), but do not normally run as root. Rather than make those programs setuid root so they can validate the user's password, PAM's normal Unix-style authentication calls unix_chkpwd to validate the password for it, so that only unix_chkpwd needs to be setuid root. Not only does this remove the need for xscreensaver to be written as a privileged program, but it also means that any vulnerabilities in the X11 libraries it depends on do not allow local exploits.

A dictionary attack is a brute force method of discovering passwords where an automated program runs through a large list of common passwords, such as words in a dictionary, until one works.

Using helper programs in this way is a very good way of eliminating the possibility of security problems in applications. Writing these helpers is normally quite straightforward, and their correctness is relatively simple to determine. There are a couple of things to watch out for in their design, however.

Quite often, confidential data is passed between the main application and the helper program. For unix_chkpwd, the user's unencrypted password must be supplied for the helper program to validate. Some care needs to be taken in how that information is passed; while it is tempting to use a command-line argument, that would allow any user who runs ps at just the right time to see a user's unencrypted passwords. If a pipe is used to transmit the data instead (normally set as the helper program's stdin), then the data is transmitted without other programs being able to see it.

The helper program also needs to carefully ensure that the program calling it is allowed to perform the action it is requesting. The unx_chkpwd helper does not let a program validate the passwords of any user other than the one running it. It uses its own real uid to validate that the program that calls it is allowed to check the password of the user it has requested. The utempter helper does similar checks to make sure that programs cannot remove terminals from the utmp database unless it is appropriate to do so.

Restricting File System Access

One more way of keeping coding mistakes from providing the potential for an attack is to limit the set of files to which a program has access by using the chroot() system call. chroot() followed by a chdir() call changes the root directory of the process, limiting the set of files that process is able to access. This does not prevent an exploit, but it can sometimes contain the damage. If a network server running as a user other than root is remotely exploited, it becomes much more difficult for that remote user to use that server as the base of a local exploit if it cannot access any setuid files (the most common programs local exploits can take advantage of).

Anonymous ftp servers are the most common programs that take advantage of the chroot() mechanism. In recent years it has become more popular in other programs, and many system administrators have used the chroot command to force system daemons into running in a restricted environment as a precaution against intruders.

Legal Disclaimer

Our website is not responsible for the information contained by this article. Webworldarticles.com is a free articles resource thus practically any visitor can submit an article. However if you notice any copyrighted material, please contact us and we will remove the article(s) in discussion right away.


This article was sent to us by: Humberto Mitchson at 07252007

Related Articles

1. Building Shared Libraries
Once you have grasped the concept of sonames, the rest is easy. Just follow a few simple rules. Build your sources with gcc's -fPIC flag. This ...

2. Designing Shared Libraries
Building shared libraries is only marginally harder than building normal static libraries. There are a few constraints, all of which are easy to manage. There is also o...

3. Shared Libraries
Shared libraries have several advantages over static libraries: Linux shares the memory used for executable code among all the processes that ...

4. Installing Shared Libraries
The ldconfig program does all the hard work of installing a shared library. You just need to put the files in place and run ldconfig. Follow these steps: ...

5. Using Shared Libraries
The easiest way to use a shared library is to ignore the fact that it is a shared library. The C compiler automatically uses shared libraries instead of static ones unl...

6. What's a Linux Process
What exactly is a process? In the original Unix implementations, a process was any executing program. For each program, the kernel kept track of ...

7. POSIX Interfaces
POSIX Required Types POSIX defines several typedefs defined in the header file <sys/types.h> and used for many arguments and return values. These typede...

8. Common Linux Security Holes
Now that we have looked at ways of reducing the potential impact of insecure code, we go over some of the most common programming mistakes that lead to security problem...

9. Emax vs. vi Unix text editors
Unix developers have traditionally held strong and diverse preferences, especially about editors. Many programmers' editors are available for you to try; the two ...