CVE-2013-4136 (published 2013-09-30T21:55Z)

ext/common/ServerInstanceDir.h in Phusion Passenger gem before 4.0.6 for Ruby allows local users to gain privileges or possibly change the ownership of arbitrary directories via a symlink attack on a directory with a predictable name in /tmp/.

Severity: MEDIUM
CVSS v2 base score: 4.4 (AV:L/AC:M/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: CWE-59
cwe_name: Improper Link Resolution Before File Access ('Link Following')
description: The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/phusion/passenger
commit_details: repo_url: https://github.com/phusion/passenger
author: Hongli Lai (Phusion)
author_date: 2013-06-27 23:26:24+02:00
msg: If the server instance directory already exists, it is now removed first in order get correct directory permissions.
If the directory still exists after removal, Phusion Passenger aborts to avoid writing to a directory with unexpected permissions.
Fixes issue #910.
repository: repo_url: https://github.com/phusion/passenger
repo_name: phusion/passenger
description: A fast and robust web server and application server for Ruby, Python and Node.js
repo_language: C++
owner: phusion
file_changes: filename: NEWS
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,10 @@ Release 4.0.6
    created with the setuid bit, when it should have sticky bit (to prevent
    existing files from being deleted or renamed by a user that doesn't own the
    file). This has now been fixed.
+ * If the server instance directory already exists, it will now be removed
+   first in order get correct directory permissions. If the directory still
+   exists after removal, Phusion Passenger aborts to avoid writing to a
+   directory with unexpected permissions. Fixes issue #910.
  * The installer now checks whether the system has enough virtual memory, and
    prints a helpful warning if it doesn't.
  * Linux/AArch64 compatibility fixes. Patch contributed by Dirk Mueller.

programming_language: Markdown
filename: ServerInstanceDir.h
change_type: ModificationType.MODIFY
diff: @@ -30,6 +30,7 @@
 #include <oxt/backtrace.hpp>
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <pwd.h>
@@ -214,7 +215,33 @@ private:
 		 * rights though, because we want admin tools to be able to list the available
 		 * generations no matter what user they're running as.
 		 */
-		makeDirTree(path, "u=rwx,g=rx,o=rx");
+		if (owner) {
+			switch (getFileType(path)) {
+			case FT_NONEXISTANT:
+				createDirectory(path);
+				break;
+			case FT_DIRECTORY:
+				removeDirTree(path);
+				createDirectory(path);
+				break;
+			default:
+				throw RuntimeException("'" + path + "' already exists, and is not a directory");
+			}
+		} else if (getFileType(path) != FT_DIRECTORY) {
+			throw RuntimeException("Server instance directory '" + path +
+				"' does not exist");
+		}
+	}
+
+	void createDirectory(const string &path) const {
+		// We do not use makeDirTree() here. If an attacker creates a directory
+		// just before we do, then we want to abort because we want the directory
+		// to have specific permissions.
+		if (mkdir(path.c_str(), parseModeString("u=rwx,g=rx,o=rx")) == -1) {
+			int e = errno;
+			throw FileSystemException("Cannot create server instance directory '" +
+				path + "'", e, path);
+		}
 	}
 	
 	bool isDirectory(const string &dir, struct dirent *entry) const {

programming_language: C++
filename: ServerInstanceDirTest.cpp
change_type: ModificationType.MODIFY
diff: @@ -58,9 +58,11 @@ namespace tut {
 	}
 	
 	TEST_METHOD(5) {
-		// The destructor doesnn't remove the server instance directory if it
+		// The destructor doesn't remove the server instance directory if it
 		// wasn't created with the ownership flag or if it's been detached.
 		string path, path2;
+		makeDirTree(parentDir + "/passenger-test.1234");
+		makeDirTree(parentDir + "/passenger-test.5678");
 		{
 			ServerInstanceDir dir(parentDir + "/passenger-test.1234", false);
 			ServerInstanceDir dir2(parentDir + "/passenger-test.5678", false);

programming_language: JavaScript