Commit message: 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.
CVE: CVE-2013-4136
CWE: CWE-61
Vulnerability description: 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/.

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(6) {
		// If there are no existing generations, newGeneration() creates a new
		// generation directory with number 0.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		unsigned int ncontents = listDir(dir.getPath()).size();
		ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true,
			"nobody", nobodyGroup, 0, 0);
		
		ensure_equals(generation->getNumber(), 0u);
		ensure_equals(getFileType(generation->getPath()), FT_DIRECTORY);
		ensure_equals(listDir(dir.getPath()).size(), ncontents + 1);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(7) {
		// A Generation object returned by newGeneration() deletes the associated
		// generation directory upon destruction.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true,
			"nobody", nobodyGroup, 0, 0);
		string path = generation->getPath();
		generation.reset();
		ensure_equals(getFileType(path), FT_NONEXISTANT);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

		ServerInstanceDirTest(): tmpDir("server_instance_dir_test.tmp") {
			parentDir = "server_instance_dir_test.tmp";
			nobodyGroup = getPrimaryGroupName("nobody");
		}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(12) {
		// A Generation object returned by getGeneration() doesn't delete the
		// associated generation directory upon destruction.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		
		dir.getGeneration(0).reset();
		dir.getGeneration(1).reset();
		ensure_equals(getFileType(generation0->getPath()), FT_DIRECTORY);
		ensure_equals(getFileType(generation1->getPath()), FT_DIRECTORY);
	}

Project: passenger
File: ServerInstanceDir.h

		void create(bool userSwitching, const string &defaultUser,
		            const string &defaultGroup, uid_t webServerWorkerUid,
		            gid_t webServerWorkerGid)
		{
			TRACE_POINT();
			bool runningAsRoot = geteuid() == 0;
			struct passwd *defaultUserEntry;
			struct group  *defaultGroupEntry;
			uid_t defaultUid;
			gid_t defaultGid;
			
			defaultUserEntry = getpwnam(defaultUser.c_str());
			if (defaultUserEntry == NULL) {
				throw NonExistentUserException("Default user '" + defaultUser +
					"' does not exist.");
			}
			defaultUid = defaultUserEntry->pw_uid;
			defaultGroupEntry = getgrnam(defaultGroup.c_str());
			if (defaultGroupEntry == NULL) {
				throw NonExistentGroupException("Default group '" + defaultGroup +
					"' does not exist.");
			}
			defaultGid = defaultGroupEntry->gr_gid;
			
			/* We set a very tight permission here: no read or write access for
			 * anybody except the owner. The individual files and subdirectories
			 * decide for themselves whether they're readable by anybody.
			 */
			makeDirTree(path, "u=rwx,g=x,o=x");
			
			/* Write structure version file. */
			string structureVersionFile = path + "/structure_version.txt";
			createFile(structureVersionFile,
				toString(SERVER_INSTANCE_DIR_GENERATION_STRUCTURE_MAJOR_VERSION) + "." +
				toString(SERVER_INSTANCE_DIR_GENERATION_STRUCTURE_MINOR_VERSION),
				S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
			
			
			/* We want the upload buffer directory to be only writable by the web
			 * server's worker processs. Other users may not have any access to this
			 * directory.
			 */
			if (runningAsRoot) {
				makeDirTree(path + "/buffered_uploads", "u=rwx,g=,o=",
					webServerWorkerUid, webServerWorkerGid);
			} else {
				makeDirTree(path + "/buffered_uploads", "u=rwx,g=,o=");
			}
			
			/* The web server must be able to directly connect to a backend. */
			if (runningAsRoot) {
				if (userSwitching) {
					/* Each backend process may be running as a different user,
					 * so the backends subdirectory must be world-writable.
					 * However we don't want everybody to be able to know the
					 * sockets' filenames, so the directory is not readable.
					 */
					makeDirTree(path + "/backends", "u=rwx,g=wx,o=wx,+t");
				} else {
					/* All backend processes are running as defaultUser/defaultGroup,
					 * so make defaultUser/defaultGroup the owner and group of the
					 * subdirecory.
					 *
					 * The directory is not readable as a security precaution:
					 * nobody should be able to know the sockets' filenames without
					 * having access to the application pool.
					 */
					makeDirTree(path + "/backends", "u=rwx,g=x,o=x", defaultUid, defaultGid);
				}
			} else {
				/* All backend processes are running as the same user as the web server,
				 * so only allow access for this user.
				 */
				makeDirTree(path + "/backends", "u=rwx,g=,o=");
			}
			
			/* The helper server (containing the application pool) must be able to access
			 * the spawn server's socket.
			 */
			if (runningAsRoot) {
				if (userSwitching) {
					/* Both the helper server and the spawn server are
					 * running as root.
					 */
					makeDirTree(path + "/spawn-server", "u=rwx,g=,o=");
				} else {
					/* Both the helper server and the spawn server are
					 * running as defaultUser/defaultGroup.
					 */
					makeDirTree(path + "/spawn-server", "u=rwx,g=,o=",
						defaultUid, defaultGid);
				}
			} else {
				makeDirTree(path + "/spawn-server", "u=rwx,g=,o=");
			}
			
			owner = true;
		}

Project: passenger
File: ServerInstanceDir.h

		~Generation() {
			if (owner) {
				removeDirTree(path);
			}
		}

Project: passenger
File: ServerInstanceDir.h

	GenerationPtr getGeneration(unsigned int number) const {
		// Must not used make_shared() here because Watchdog.cpp
		// deletes the raw pointer in cleanupAgentsInBackground().
		return ptr(new Generation(path, number));
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(8) {
		// getNewestGeneration() returns the newest generation.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation2 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation3 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		
		generation2.reset();
		ensure_equals(dir.getNewestGeneration()->getNumber(), 3u);
		generation3.reset();
		ensure_equals(dir.getNewestGeneration()->getNumber(), 1u);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(5) {
		// 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);
			dir2.detach();
			path = dir.getPath();
			path2 = dir2.getPath();
		}
		ensure_equals(getFileType(path), FT_DIRECTORY);
		ensure_equals(getFileType(path2), FT_DIRECTORY);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

		void createGenerationDir(const string &instanceDir, unsigned int number) {
			string command = "mkdir " + instanceDir + "/generation-" + toString(number);
			runShellCommand(command.c_str());
		}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(13) {
		// A detached Generation doesn't delete the associated generation
		// directory upon destruction.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		string path = generation->getPath();
		generation->detach();
		generation.reset();
		ensure_equals(getFileType(path), FT_DIRECTORY);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(2) {
		// The (string) constructor creates a ServerInstanceDir object that's
		// associated with the given directory, and creates the directory
		// if it doesn't exist.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir dir2(dir.getPath());
		ServerInstanceDir dir3(parentDir + "/foo");
		ensure_equals(dir2.getPath(), dir.getPath());
		ensure_equals(dir3.getPath(), parentDir + "/foo");
		ensure_equals(getFileType(dir3.getPath()), FT_DIRECTORY);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(4) {
		// The destructor does not throw any exceptions if the server instance
		// directory doesn't exist anymore.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		removeDirTree(dir.getPath());
	}

Project: passenger
File: ServerInstanceDir.h

	~ServerInstanceDir() {
		if (owner) {
			GenerationPtr newestGeneration;
			try {
				newestGeneration = getNewestGeneration();
			} catch (const FileSystemException &e) {
				if (e.code() == ENOENT) {
					return;
				} else {
					throw;
				}
			}
			if (newestGeneration == NULL) {
				removeDirTree(path);
			}
		}
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(11) {
		// getGeneration() returns the given generation.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation0 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation1 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation2 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr generation3 = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		
		ensure_equals(dir.getGeneration(0)->getNumber(), 0u);
		ensure_equals(dir.getGeneration(3)->getNumber(), 3u);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(10) {
		// A Generation object returned by getNewestGeneration() doesn't delete
		// the associated generation directory upon destruction.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir::GenerationPtr generation = dir.newGeneration(true, "nobody", nobodyGroup, 0, 0);
		ServerInstanceDir::GenerationPtr newestGeneration = dir.getNewestGeneration();
		newestGeneration.reset();
		ensure_equals(getFileType(generation->getPath()), FT_DIRECTORY);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(14) {
		// It's possible to have two ServerInstanceDir objects constructed
		// with the same (pid_t, string) constructor arguments.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ServerInstanceDir dir2(parentDir + "/passenger-test.1234");
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(3) {
		// A ServerInstanceDir object removes the server instance directory
		// upon destruction, but only if there are no more generations in it.
		{
			ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		}
		ensure_equals(listDir(parentDir).size(), 0u);
		
		{
			ServerInstanceDir dir(parentDir + "/passenger-test.1234");
			createGenerationDir(dir.getPath(), 1);
		}
		ensure_equals(listDir(parentDir).size(), 1u);
	}

Project: passenger
File: ServerInstanceDirTest.cpp

	TEST_METHOD(9) {
		// getNewestGeneration returns null if there are no generations.
		ServerInstanceDir dir(parentDir + "/passenger-test.1234");
		ensure(dir.getNewestGeneration() == NULL);
	}