Xref: utzoo comp.unix.wizards:7006 comp.bugs.sys5:360 Path: utzoo!mnetor!uunet!lll-winken!lll-tis!ames!umd5!uvaarpa!virginia!scl From: scl@virginia.acc.virginia.edu (Steve Losen) Newsgroups: comp.unix.wizards,comp.bugs.sys5 Subject: Re: Guide to writing secure setuid programs? Message-ID: <700@virginia.acc.virginia.edu> Date: 11 Mar 88 16:40:40 GMT References: <181@wsccs.UUCP> <722@rivm05.UUCP> <1037@woton.UUCP> Reply-To: scl@virginia.acc.Virginia.EDU (Steve Losen) Organization: University of Va., Charlottesville, VA Lines: 88 I have no guide for writing setuid programs, but here are a few ideas that come to mind: 1) There's a big difference between setuid to root and setuid to an ordinary user. This should be obvious because of the many operations that only root can do. One should always endeaver to make a program setuid to some non-root user if at all possible. If a program is setuid to a non-root user it should revert back to the real user whenever possible so that the program can access all of the user's files. We all know what a pain it is that lp(1) can't open any files that user "lp" can't access (which may include files that the real user can access.) 2) Avoid setuid if you can. I once wrote a very simple print spooler that puts files in a directory where they are picked up periodically by a daemon to be printed. I made the directory 777 instead of using setuid-to-lp fraud. Sure a malicious user can remove files in the print queue. So what? To my knowlege, no one has ever done that in the two years since I put the system up. Ask yourself, "Does this really need to be setuid?" For example, I would *never* make a program setuid just so it could write to a protected logfile. To hell with it. make the logfile 622. 3) Have the setuid program grab all necessary resources at the beginning and revert back to the real user. For example, once you open a file you can revert back to the real user before reading or writing. This little trick can be very handy for instructors who want their students to turn in assignments to the instructor's protected directory from the student's protected directory. Sound like job for root? Nope! Write a setuid-to-instructor program that creat(2)'s a file in the instructors protected directory. Now revert back to the real user (the student), open the assignment, and copy it to the fd that was creat(2)'ed earlier. As a matter of fact, I heard a horror story about another such turn-un program. The program was setuid to root and it prompted for source and destination file names. The source name was appended to the student's home directory while the destination name was appended to the instructor's "turn-in" directory and the copy was done. Unfortunately, the programmer forgot about "../../.." and students quickly learned that they could copy any file anywhere with this program. (This was taken from comp.risks, a newsgroup I highly recommend.) Another thing you can do is set up a system so that all of its sensitive files and directories are within a single subtree. Make the directory at the top of the subtree 700 to keep ordinary users out. But within the subtree loosen the permissions. Make directories where users will create files 777. Make logfiles 622. Each program that manipulates this system is setuid to the owner of the protected directory. Upon invocation, the process chdirs below the protected directory and reverts back to the real user. Now the process can access both the user's files and the sensitive system files. This sort of design would have solved the problem with lp(1). 4) Instead of making a whole program setuid, identify the portions that need special privilege and write small, very specific setuid programs to do those tasks. Fork and/or exec the small programs from the main program. We once had a program that needed to signal another process that was owned by a different user. Instead of making the first process setuid to root, we wrote a small setuid to root program to send the signal. To keep normal users from running the little program we put it in a special group with mode 4110 and made the first program setgid to the special group. 5) If you MUST write a setuid to root program be VERY careful when checking any input or arguments from a user. Realize that root can do amazing things that even an administrator would never do. Take unlink(2) in SysV, for example. Root can unlink a directory, disconnecting from the file system any files that were in the directory. Fsck is the only way to relink those files. So even if you do an access(2) and find out that "yes, the real user can remove file foo" be sure that "foo" is not a directory. Root can also unlink "." and ".." . Another example is mount(2). You have to be root to mount a floppy on a 3b2. If you write a setuid program for your users to mount floppies, you better check carefully where the user wants to mount or she could put her own "passwd" file on the floppy and mount it on /etc. In a similar vein, when running in "root" mode, realize that environment variables are easy to fake. Never use the PATH environment variable; always fully specify the pathnames of any process you exec. If you exec a process as root, you might want to clear the environment first. Use getpwent instead of $HOME. Well this is certainly a lot more than I first intended to say. -- Steve Losen scl@virginia.edu University of Virginia Academic Computing Center