CVE-2014-1832 (C, published 2015-02-19T15:59Z)
Description: value: Phusion Passenger 4.0.37 allows local users to write to certain files and directories via a symlink attack on (1) control_process.pid or a (2) generation-* file.  NOTE: this vulnerability exists because of an incomplete fix for CVE-2014-1831.
Severity: LOW (CVSS v3 base score: )
Weakness: NVD-CWE-Other \u2014 Other
NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
Repository: https://github.com/phusion/passenger
Files changed:
NEWS
ext/common/ServerInstanceDir.h
ext/common/Utils.cpp
ext/common/Utils.h
Commit message: Fix a symlink-related security vulnerability.

The fix in commit 34b10878 and contained a small attack time window in
between two filesystem operations. This has been fixed.


Vulnerable code:
 *  Copyright (c) 2010-2013 Phusion
			switch (getFileTypeNoFollowSymlinks(path)) {
			case FT_NONEXISTANT:
				break;
			case FT_DIRECTORY:
				verifyDirectoryPermissions(path);
				break;
			default:
				throw RuntimeException("'" + path + "' already exists, and is not a directory");
		} else if (getFileType(path) != FT_DIRECTORY) {
	void verifyDirectoryPermissions(const string &path) {
		struct stat buf;
		if (stat(path.c_str(), &buf) == -1) {
			int e = errno;
			throw FileSystemException("Cannot stat() " + path, e, path);
		} else if (buf.st_mode != (S_IFDIR | parseModeString("u=rwx,g=rx,o=rx"))) {
FileType
getFileTypeNoFollowSymlinks(const StaticString &filename) {
	struct stat buf;
	int ret;
	
	ret = lstat(filename.c_str(), &buf);
	if (ret == 0) {
		if (S_ISREG(buf.st_mode)) {
			return FT_REGULAR;
		} else if (S_ISDIR(buf.st_mode)) {
			return FT_DIRECTORY;
		} else if (S_ISLNK(buf.st_mode)) {
			return FT_SYMLINK;
		} else {
			return FT_OTHER;
		}
	} else {
		if (errno == ENOENT) {
			return FT_NONEXISTANT;
		} else {
			int e = errno;
			string message("Cannot lstat '");
			message.append(filename);
			message.append("'");
			throw FileSystemException(message, e, filename);
		}
	}
}

	/** A symlink. Only returned by getFileTypeNoFollowSymlinks(), not by getFileType(). */
	FT_SYMLINK,
/**
 * Like getFileType(), but does not follow symlinks.
 */
FileType getFileTypeNoFollowSymlinks(const StaticString &filename);

Fixed code:
Release 4.0.38
--------------

 * Fixed a symlink-related security vulnerability.

   Urgency: low
   Scope: local exploit
   Summary: writing files to arbitrary directory by hijacking temp directories
   Affected versions: 4.0.37
   Fixed versions: 4.0.38

   Description:
   This issue is related to the security issue as mentioned in the 4.0.37
   release notes. The previous fix was incomplete, and still has a
   (albeit smaller) small attack time window in between two filesystem
   checks. This attack window is now gone.


 *  Copyright (c) 2010-2014 Phusion
		struct stat buf;
		int ret;


		do {
			ret = lstat(path.c_str(), &buf);
		} while (ret == -1 && errno == EAGAIN);
			if (ret == 0) {
				if (S_ISDIR(buf.st_mode)) {
					verifyDirectoryPermissions(path, buf);
				} else {
					throw RuntimeException("'" + path + "' already exists, and is not a directory");
				}
			} else if (errno == ENOENT) {
			} else {
				int e = errno;
				throw FileSystemException("Cannot lstat '" + path + "'",
					e, path);
		} else if (!S_ISDIR(buf.st_mode)) {
	void verifyDirectoryPermissions(const string &path, struct stat &buf) {
		if (buf.st_mode != (S_IFDIR | parseModeString("u=rwx,g=rx,o=rx"))) {