Bugzilla – Bug 4647
Insecure temporary file handling in the Globus Toolkit
Last modified: 2008-01-11 15:56:54
You need to log in before you can comment on or make changes to this bug.
Insecure temporary file handling in the Globus Toolkit Alex Lambert lamberta@ncsa.uiuc.edu Background In my work with MyProxy, I found a temporary file handling vulnerability. While researching this issue, I found similar issues in other components of the Globus Toolkit. Temporary file use today myproxy-admin-adduser is a Perl script that an administrator runs (as root) to add a user to the local MyProxy database. $certfile = "/tmp/myproxy_adduser_cert.pem"; $reqfile = "/tmp/myproxy_adduser_cert_request.pem"; $keyfile = "/tmp/myproxy_adduser_key.pem"; ... system("grid-ca-sign", "-in", $reqfile, "-out", $certfile, "-force"); system("myproxy-admin-load-credential", "-c", $certfile, "-y", $keyfile); grid-ca-sign is a shell script that signs a given certificate request. It is invoked internally by myproxy-admin-adduser; it can also be run on its own. It is part of the SimpleCA package. TMP_REQ_FILE=/tmp/tmp_cert_req.pem.$$ TMP_CERT_FILE=/tmp/tmp_cert.pem.$$ cp ${INPUT_REQ_FILE} ${TMP_REQ_FILE} ... openssl ca ... -in ${TMP_REQ_FILE} -out ${TMP_CERT_FILE} grid-security-config is a shell script that installs a new certificate authority. It is run by setup-gsi after a new CA package is installed. Each CA package created by SimpleCA includes a customized version of grid-security-config. (The following is from the Globus Certificate Service package.) TEMP_FILE1=/tmp/grid-security-config_1.$$ ... cp ${TEMP_FILE1} /etc/grid-security.conf.b38b4d8c The problem A secure program ensures that each temporary file is exclusively under its control. Several Globus tools fail to take appropriate precautions before using temporary files. Attacks The attacker can set up a link from the temporary file to a sensitive file. For example, linking /tmp/myproxy_adduser_key.pem to /etc/passwd would cause the password file to be overwritten with a certificate request the next time myproxy-admin-adduser is run. The attacker can also create the file himself and set relaxed permissions. For example, an attacker could create /tmp/grid-security-config_1.$$ as a world-readable, world-writable file. The attacker could examine and modify the temporary file as grid-security-config is running. (The attacker would need to know the process ID of grid-security-config. Predicting a process ID is easy on many systems. Alternatively, he could create a file for each of the system's possible process IDs.) Real-world exploits I have exploits for both myproxy-admin-adduser and grid-ca-sign. An attacker can force the CA to sign an arbitrary certificate request. The attacker must be able to write to files in /tmp and win several race conditions. The method is the same for both targets: create a world-writable file in /tmp with the appropriate name, and then replace the temporary certificate request with a request generated by the attacker at the appropriate time. I also have a exploit for grid-security-config. An attacker can gain the privileges of the user running the setup-gsi script (usually, root). The attacker must be able to write to files in /tmp and win several race conditions. The grid-security.conf file is a shell script. After the temporary grid-security.conf file is written, the attacker appends his own commands to the end of the file. (In my particular exploit, I drop a setuid copy of /bin/sh into /tmp.) Later in the setup process, when the configuration file is sourced by grid-cert-request-config, the attacker's commands are executed. I have not evaluated the feasibility of winning the race conditions in any of these exploits. Fixing the problem in C The mkstemp(3) function securely creates a temporary file. It accepts one argument, a pointer to the first character of a string containing a template for the file name. Trailing 'X' characters in the template are replaced with random characters. For example, the template /home/lamberta/.tmp/globus-XXXXXXXXXX could become /home/lamberta/.tmp/globus-iYthHkHFfW. The secure temporary file algorithm (used in mkstemp(3)) is: create a random file name based on the template try to open() that file with flags O_CREAT | O_EXCL O_CREAT is "create the file if it does not exist" O_EXCL is "fail if the file already exists" if successful, stop and return the file name; otherwise, repeat Fixing the problem in Perl: myproxy-admin-adduser A Perl module, File::Temp, provides for secure temporary file creation. File::Temp is included with Perl 5.6.1 and later. (I have submitted a patch for myproxy-admin-adduser.) Python has a similar module, tempfile. Fixing the problem in shell scripts: grid-ca-sign, grid-security-config No widely-portable mechanism exists for securely creating temporary files in shell scripts. In general, there is no way to open a file with flags O_CREAT | O_EXCL in a shell script. One workaround is to create a temporary directory and then store files within that directory. This works because the mkdir(1) command will fail if the directory already exists. (The GNU libc documentation says that "directory creation always works like open with O_EXCL.") Another workaround is to use an external utility to implement temporary file creation. mktemp(1), first implemented in OpenBSD, is a wrapper around mkstemp(3). It is present in recent Linux and BSD systems, but it is not installed by default on (e.g.) Solaris < 10. Scope of the problem I downloaded the Globus CVS repository and ran grep with strings like "/tmp" and "$$". I found a number of places in which temporary files may be used insecurely. (I have not done more than a casual inspection of each instance, though.) * gsi/ssl_utils/source/library/sslutils.c proxy_marshal_tmp() (writes a user's proxy!) * common/source/library/globus_object_hierarchy.h.sh * common/source/programs/globus-sh-exec.in * data_management/multirft/src/org/globus/ogsa/impl/base/multirft/TransferClient.java noTptNonExtendedTransfer() noTptTransfer() * gram/jobmanager/source/globus_gram_job_manager_request.c globus_gram_job_manager_request_open_logfile() * gsi/{cert,ssl}_utils/source/programs/grid-cert-renew.in * gsi/simple_ca/setup/setup-simple-ca generate_ca_certificate() * io/source/library/globus_io_error_hierarchy.h.sh * ogsa-c/build_tools/cvs-build-ogsa my_system() * replica/rls/client/java/RLSGui.java actionPerformed() * replica/rls/server/conf.c conf_read() * workspace/vm/backend/workspace/vms/xen/xen_v2.py run_guc() * ws-rendezvous/client/c/test/rendezvous-notification-test.pl * ws-transfer/reliable/client/c/crft_util/test/simple-trans.pl For many of these issues, the fix is easy: use the language's implementation of mkstemp(3). There is no straightforward solution for fixing the shell scripts, though. A general solution for shell scripts It is not reasonable to expect that mktemp(1) is installed on every machine running Globus. Globus already has a small library for handling command-line arguments in shell scripts. Another small library, for safe temporary file handling, should be added. The temporary file library for Globus shell scripts The library is just a simple wrapper around mktemp(1) and mkdir(1). Several convenience functions could exist; they would wrap globus_create_temp(). Psuedocode for globus_create_temp(): globus_create_temp(is_file, prefix, parent, perms): if is_file set umask; try mktemp $parent/$prefix-XXXXXXXXXX if successful set permissions return name else /* mktemp didn't work */ fail else /* is directory */ set umask; try mktemp -d $parent/$prefix-XXXXXXXXXX if successful set permissions return name else /* mktemp didn't work */ set umask; try mkdir $parent/$prefix-$$-${RANDOM}... if successful set permissions return name else /* mkdir didn't work */ fail Since creating a temporary file will fail on systems without mktemp(1), existing scripts should be changed to use files within temporary directories. If a directory is requested and mktemp(1) is not available, the function will attempt to generate a unique directory name. The name consists of the appropriate prefix, the process ID, and several random numbers from ${RANDOM}, a built-in random number generator present in some shells. The shell's PRNG is not likely to be cryptographically strong, and not all shells implement ${RANDOM}. (Perhaps we can use OpenSSL's command-line utility instead...) It is possible that an attacker will be able to predict the name of the temporary directory and create it before the script can; in this case, the directory creation will fail. Scripts must be modified to safely handle this situation. A complication Michal Zalweski proposed that even mkstemp(3) is insufficient for safely creating temporary files in /tmp. He says: 'tmpwatch' is a handy utility that removes files which haven't been accessed for a period of time...By default, it is installed with a crontab entry that sweeps /tmp directory on a daily basis, deleting files that have not been accessed for past few days...Numerous Linux systems, such as Red Hat, ship with cron daemon running and 'tmpwatch' configured to sweep /tmp. He suggests that if it is possible to force a process to pause for several days (either by sending it SIGSTOP, or by creating a large amount of work), a tmpwatch-like utility could remove a file that is still in use. The attacker could then take control of the file. Zalweski recommends avoiding /tmp and using private temporary directories (e.g. in the user's home) whenever possible. All of the Globus applications that I have seen would work with a private temporary directory. Future solutions The mktemp(1) utility is under the BSD license. Additionally, the author states, "If you are an OS vendor who would like to bundle mktemp(1) but its license is unacceptable to you, please contact me - we can probably work something out." Could mktemp(1) be included or made a prerequisite in a future version of the Toolkit? Sources Python Library Reference: tempfile http://docs.python.org/lib/module-tempfile.html mktemp(1) http://www.mktemp.org/mktemp/ "Common use of 'tmpwatch' utility and alikes triggers race conditions," Michal Zalewski http://lcamtuf.coredump.cx/tmp_paper.txt "Secure Programming for Linux and Unix HOWTO: Temporary Files," David Wheeler http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO "Safely creating temporary files in shell scripts," Stefan Nordhausen http://www.linuxsecurity.com/content/view/115462/151/ The GNU C Library: Temporary Files http://www.gnu.org/software/libc/manual/html_node/Temporary-Files.html Changes in Perl 5.6.1 http://perldoc.perl.org/perl561delta.html Perl Documentation: File::Temp http://perldoc.perl.org/File/Temp.html
Summary of Java side fixes: A utility method has been added to CoG (org.globus.util.Util::createFile), that can be used to "securely" create a file. That method checks if file already exists, if so tries to delete it and create again. If either deletion of old file or creation of new one fails for any reason, an exception is thrown. The "Util.setPermissions(fileName, 600)" method has been encapsulated into a separate method, setOwnerAccessOnly(fileName). All files created in GSI code in CoG and the Java WS Security code has been updated to use the above utility to create file and set permissions before anything is written to the file. These fixes have been pushed to trunk, 4.0 branch and community branch. No soulution has been found to atomically create a file and set relevant permissions as yet. The current plan is to add a note about it in the advisory and ask folks to use a umask that would restrict access created to the file.
A few of these are not real problems: * gsi/ssl_utils/source/library/sslutils.c proxy_marshal_tmp() (writes a user's proxy!) * gsi/ssl_utils/source/programs/grid-cert-renew.in The ssl_utils package is obsolete since GT 2, so these aren't an issue. I've removed these from 3.2 branch and the trunk. joe
RFT related updates: John removed ws-transfer/reliable/client/c/crft_util/test/simple-trans.pl as it is not being used at all. I will fix the other two files under data-management/multirft once new cog jar with utility api is added to 3.2 cvs.
grid-cert-renew is also not part of any 3.2 or later distribution (included, but not in the makefile so never seen). I committed fix for gsi/simple_ca/setup/setup-simple-ca to 3.2, 4.0, 4.0 community, and trunk joe
Since grid-cert-renew isn't installed by the Makefile.am, I removed grid-cert-renew.in and the configure.in line which creates it from the cert_utils/source package joe
ws-gram (trunk and 4.0 branch) code uses File.createTemp file and sets permissions for a temporary file it creates and other file write is to $G_L/var. The delegated proxy is written out to file using a tool, but to ~/.globus directory, so no issues there. ws-rendezvous does not have any file access.
Created an attachment (id=1028) [details] Fixes for patching the Java Components
Fixes for myproxy have been committed to myproxy cvs head.
Temp file creations are fixed in ws-transfer in globus_4_0_branch and trunk. Still need to fix globus_3_2_branch
1) Java GSI: Fixes committed to trunk, globus_4_0_branch, globus_4_0_community and globus_3_2_branch. 2) CAS: Fixes applied to all branches. 3) Delegation Service: No fixes were required, since only persistence of resource uses files. 4) GRAM: No fixes were required in Java code in any of the branches. 4.x code uses some tools to write out proxy and Joe Bester reviewed that code, no fixes were required.
No file handling code was found in ws-rendezvous module.
Created an attachment (id=1029) [details] Update Java Component fixes
Dynamic accounts, virtual workspaces, and GridShib are not currently released with GT. The python temp file use in the candidate list under workspace/ is from code in development, these issues will be addressed before next release.
Fixes committed in globus_3_2_branch and multirft under ogsa trunk.
Committed changes to job manager to use mkstemp for script interface files. Don't fall back to writing a log file in /tmp if /home is not writable.
* io/source/library/globus_io_error_hierarchy.h.sh This is not part of any supported release. It was replaced by xio and io/compat in 3.2.
WS-MDS is now okay (there were minor problems with two test programs, neither of which is run by default. 3.2 MDS looks like it has a few issues in information providers; I'm working on those now.
Committed fixes to c wsrf core tests, ws-rendezvous and ws-gram tests. Add new perl module to globus_c_wsrf_core_tools to start containers without using any files in /tmp and updated tests to use that. Committed fix to pre-ws GRAM to use mkstemp for creating files in /tmp joe
Committed fix to globus_rls_server to prevent inadvertent use of /tmp for bloom filter storage. Fixed in trunk, globus_4_0_branch, and globus_3_2_branch. No other fixes pending for RLS or DRS.
Checked in 3.2 MDS fixes.
Security Advisory: http://www-unix.globus.org/mail_archive/security-announce/2006/08/msg00001.html