diff -u suphp-0.6.2/debian/patches/00list suphp-0.6.2/debian/patches/00list --- suphp-0.6.2/debian/patches/00list +++ suphp-0.6.2/debian/patches/00list @@ -3,0 +4 @@ +10_CVE-2008-1614.dpatch diff -u suphp-0.6.2/debian/control suphp-0.6.2/debian/control --- suphp-0.6.2/debian/control +++ suphp-0.6.2/debian/control @@ -1,7 +1,8 @@ Source: suphp Section: web Priority: optional -Maintainer: Emmanuel Lacour +Maintainer: Ubuntu MOTU Developers +XSBC-Original-Maintainer: Emmanuel Lacour Build-Depends: debhelper (>> 4.1.16), apache2-prefork-dev (>= 2.2.0), apache2-mpm-prefork (>= 2.2.0) | apache2-mpm-worker (>= 2.2.0), libapr1-dev, docbook-to-man, pkg-config, dpatch Standards-Version: 3.7.2 diff -u suphp-0.6.2/debian/changelog suphp-0.6.2/debian/changelog --- suphp-0.6.2/debian/changelog +++ suphp-0.6.2/debian/changelog @@ -1,3 +1,15 @@ +suphp (0.6.2-2ubuntu1) hardy; urgency=low + + * SECURITY UPDATE: privilege escalation via race condition (LP: #216245) + - debian/patches/10_CVE-2008-1614.dpatch: Fix race condition in symlink + handling. Patch from Debian. + - References: + + CVE-2008-1614 + * Modify Maintainer value to match the DebianMaintainerField + specification. + + -- William Grant Sat, 19 Apr 2008 21:12:27 +1000 + suphp (0.6.2-2) unstable; urgency=low * remove apache 1.x package (closes: #429079) only in patch2: unchanged: --- suphp-0.6.2.orig/debian/patches/10_CVE-2008-1614.dpatch +++ suphp-0.6.2/debian/patches/10_CVE-2008-1614.dpatch @@ -0,0 +1,297 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 10_CVE-2008-1614.dpatch by William Grant +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad suphp-0.6.2~/src/API.hpp suphp-0.6.2/src/API.hpp +--- suphp-0.6.2~/src/API.hpp 2005-11-27 06:29:02.000000000 +1100 ++++ suphp-0.6.2/src/API.hpp 2008-04-19 20:51:37.000000000 +1000 +@@ -157,6 +157,12 @@ + virtual GroupInfo File_getGroup(const File& file) const + throw (SystemException) =0; + ++ /** ++ * Checks whether a file is a symlink ++ */ ++ virtual bool File_isSymlink(const File& file) const ++ throw (SystemException) =0; ++ + /** + * Runs another program (replaces current process) + */ +diff -urNad suphp-0.6.2~/src/API_Linux.cpp suphp-0.6.2/src/API_Linux.cpp +--- suphp-0.6.2~/src/API_Linux.cpp 2006-09-26 00:09:45.000000000 +1000 ++++ suphp-0.6.2/src/API_Linux.cpp 2008-04-19 20:51:37.000000000 +1000 +@@ -225,10 +225,10 @@ + + bool suPHP::API_Linux::File_exists(const File& file) const { + struct stat dummy; +- if (::stat(file.getPath().c_str(), &dummy) == 0) +- return true; ++ if (::lstat(file.getPath().c_str(), &dummy) == 0) ++ return true; + else +- return false; ++ return false; + } + + std::string suPHP::API_Linux::File_getRealPath(const File& file) const +@@ -304,7 +304,7 @@ + bool suPHP::API_Linux::File_hasPermissionBit(const File& file, FileMode perm) + const throw (SystemException) { + struct stat temp; +- if (stat(file.getPath().c_str(), &temp) == -1) { ++ if (lstat(file.getPath().c_str(), &temp) == -1) { + throw SystemException(std::string("Could not stat \"") + + file.getPath() + "\": " + + ::strerror(errno), __FILE__, __LINE__); +@@ -362,7 +362,7 @@ + UserInfo suPHP::API_Linux::File_getUser(const File& file) const + throw (SystemException) { + struct stat temp; +- if (stat(file.getPath().c_str(), &temp) == -1) { ++ if (lstat(file.getPath().c_str(), &temp) == -1) { + throw SystemException(std::string("Could not stat \"") + + file.getPath() + "\": " + + ::strerror(errno), __FILE__, __LINE__); +@@ -373,7 +373,7 @@ + GroupInfo suPHP::API_Linux::File_getGroup(const File& file) const + throw (SystemException) { + struct stat temp; +- if (stat(file.getPath().c_str(), &temp) == -1) { ++ if (lstat(file.getPath().c_str(), &temp) == -1) { + throw SystemException(std::string("Could not stat \"") + + file.getPath() + "\": " + + ::strerror(errno), __FILE__, __LINE__); +@@ -382,6 +382,11 @@ + } + + ++bool suPHP::API_Linux::File_isSymlink(const File& file) const throw (SystemException) { ++ return this->isSymlink(file.getPath()); ++} ++ ++ + void suPHP::API_Linux::execute(std::string program, const CommandLine& cline, + const Environment& env) const + throw (SystemException) { +diff -urNad suphp-0.6.2~/src/API_Linux.hpp suphp-0.6.2/src/API_Linux.hpp +--- suphp-0.6.2~/src/API_Linux.hpp 2005-11-27 06:29:02.000000000 +1100 ++++ suphp-0.6.2/src/API_Linux.hpp 2008-04-19 20:51:37.000000000 +1000 +@@ -169,6 +169,11 @@ + virtual GroupInfo File_getGroup(const File& file) const + throw (SystemException); + ++ /** ++ * Checks whether a file is a symlink ++ */ ++ virtual bool File_isSymlink(const File& file) const throw (SystemException); ++ + /** + * Runs another program (replaces current process) + */ +diff -urNad suphp-0.6.2~/src/Application.cpp suphp-0.6.2/src/Application.cpp +--- suphp-0.6.2~/src/Application.cpp 2006-02-06 07:21:03.000000000 +1100 ++++ suphp-0.6.2/src/Application.cpp 2008-04-19 20:51:37.000000000 +1000 +@@ -177,6 +177,7 @@ + throw (SystemException, SoftException) { + Logger& logger = API_Helper::getSystemAPI().getSystemLogger(); + File scriptFile = File(scriptFilename); ++ File realScriptFile = File(scriptFile.getRealPath()); + + // Check wheter file exists + if (!scriptFile.exists()) { +@@ -184,11 +185,13 @@ + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } +- +- // Get full path to script file +- +- File realScriptFile = File(scriptFile.getRealPath()); +- File directory = realScriptFile.getParentDirectory(); ++ if (!realScriptFile.exists()) { ++ std::string error = "File " + realScriptFile.getPath() ++ + " referenced by symlink " +scriptFile.getPath() ++ + " does not exist"; ++ logger.logWarning(error); ++ throw SoftException(error, __FILE__, __LINE__); ++ } + + // Check wheter script is in docroot + if (realScriptFile.getPath().find(config.getDocroot()) != 0) { +@@ -213,8 +216,19 @@ + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } ++ if (config.getCheckVHostDocroot() ++ && scriptFile.getPath().find(environment.getVar("DOCUMENT_ROOT")) ++ != 0) { ++ ++ std::string error = "File \"" + scriptFile.getPath() ++ + "\" is not in document root of Vhost \"" ++ + environment.getVar("DOCUMENT_ROOT") + "\""; ++ logger.logWarning(error); ++ throw SoftException(error, __FILE__, __LINE__); ++ } + +- // Check script and directory permissions ++ // Check script permissions ++ // Directories will be checked later + if (!realScriptFile.hasUserReadBit()) { + std::string error = "File \"" + realScriptFile.getPath() + + "\" not readable"; +@@ -231,14 +245,6 @@ + throw SoftException(error, __FILE__, __LINE__); + } + +- if (!config.getAllowDirectoryGroupWriteable() +- && directory.hasGroupWriteBit()) { +- std::string error = "Directory \"" + directory.getPath() +- + "\" is writeable by group"; +- logger.logWarning(error); +- throw SoftException(error, __FILE__, __LINE__); +- } +- + if (!config.getAllowFileOthersWriteable() + && realScriptFile.hasOthersWriteBit()) { + std::string error = "File \"" + realScriptFile.getPath() +@@ -247,14 +253,6 @@ + throw SoftException(error, __FILE__, __LINE__); + } + +- if (!config.getAllowDirectoryOthersWriteable() +- && directory.hasOthersWriteBit()) { +- std::string error = "Directory \"" + directory.getPath() +- + "\" is writeable by others"; +- logger.logWarning(error); +- throw SoftException(error, __FILE__, __LINE__); +- } +- + // Check UID/GID of symlink is matching target + if (scriptFile.getUser() != realScriptFile.getUser() + || scriptFile.getGroup() != realScriptFile.getGroup()) { +@@ -274,7 +272,8 @@ + UserInfo targetUser; + GroupInfo targetGroup; + +- File scriptFile = File(File(scriptFilename).getRealPath()); ++ File scriptFile = File(scriptFilename); ++ File realScriptFile = File(scriptFile.getRealPath()); + API& api = API_Helper::getSystemAPI(); + Logger& logger = api.getSystemLogger(); + +@@ -360,7 +359,11 @@ + throw SoftException(error, __FILE__, __LINE__); + } + #endif // OPT_USERGROUP_PARANOID +- ++ ++ // Check directory ownership and permissions ++ checkParentDirectories(realScriptFile, targetUser, config); ++ checkParentDirectories(scriptFile, targetUser, config); ++ + // Common code used for all modes + + // Set new group first, because we still need super-user privileges +@@ -480,6 +483,43 @@ + } + + ++void suPHP::Application::checkParentDirectories(const File& file, ++ const UserInfo& owner, ++ const Configuration& config) const throw (SoftException) { ++ File directory = file; ++ Logger& logger = API_Helper::getSystemAPI().getSystemLogger(); ++ do { ++ directory = directory.getParentDirectory(); ++ ++ UserInfo directoryOwner = directory.getUser(); ++ if (directoryOwner != owner && !directoryOwner.isSuperUser()) { ++ std::string error = "Directory " + directory.getPath() ++ + " is not owned by " + owner.getUsername(); ++ logger.logWarning(error); ++ throw SoftException(error, __FILE__, __LINE__); ++ } ++ ++ if (!directory.isSymlink() ++ && !config.getAllowDirectoryGroupWriteable() ++ && directory.hasGroupWriteBit()) { ++ std::string error = "Directory \"" + directory.getPath() ++ + "\" is writeable by group"; ++ logger.logWarning(error); ++ throw SoftException(error, __FILE__, __LINE__); ++ } ++ ++ if (!directory.isSymlink() ++ && !config.getAllowDirectoryOthersWriteable() ++ && directory.hasOthersWriteBit()) { ++ std::string error = "Directory \"" + directory.getPath() ++ + "\" is writeable by others"; ++ logger.logWarning(error); ++ throw SoftException(error, __FILE__, __LINE__); ++ } ++ } while (directory.getPath() != "/"); ++} ++ ++ + int main(int argc, char **argv) { + try { + API& api = API_Helper::getSystemAPI(); +diff -urNad suphp-0.6.2~/src/Application.hpp suphp-0.6.2/src/Application.hpp +--- suphp-0.6.2~/src/Application.hpp 2005-02-28 04:53:05.000000000 +1100 ++++ suphp-0.6.2/src/Application.hpp 2008-04-19 20:51:37.000000000 +1000 +@@ -107,6 +107,14 @@ + const Configuration& config) const + throw (SoftException); + ++ ++ /** ++ * Checks ownership and permissions for parent directories ++ */ ++ void checkParentDirectories(const File& file, ++ const UserInfo& owner, ++ const Configuration& config) const ++ throw (SoftException); + + public: + /** +diff -urNad suphp-0.6.2~/src/File.cpp suphp-0.6.2/src/File.cpp +--- suphp-0.6.2~/src/File.cpp 2005-02-28 04:53:05.000000000 +1100 ++++ suphp-0.6.2/src/File.cpp 2008-04-19 20:51:37.000000000 +1000 +@@ -57,6 +57,9 @@ + File suPHP::File::getParentDirectory() const { + std::string path = this->getPath(); + path = path.substr(0, path.rfind('/')); ++ if (path.length() == 0) { ++ path = "/"; ++ } + return File(path); + } + +@@ -104,3 +107,7 @@ + GroupInfo suPHP::File::getGroup() const throw (SystemException) { + return API_Helper::getSystemAPI().File_getGroup(*this); + } ++ ++bool suPHP::File::isSymlink() const throw (SystemException) { ++ return API_Helper::getSystemAPI().File_isSymlink(*this); ++} +diff -urNad suphp-0.6.2~/src/File.hpp suphp-0.6.2/src/File.hpp +--- suphp-0.6.2~/src/File.hpp 2005-02-28 04:53:05.000000000 +1100 ++++ suphp-0.6.2/src/File.hpp 2008-04-19 20:51:37.000000000 +1000 +@@ -143,7 +143,11 @@ + * Returns owning group of file + */ + GroupInfo getGroup() const throw (SystemException); +- ++ ++ /** ++ * Checks whether this file is a symlink ++ */ ++ bool isSymlink() const throw (SystemException); + }; + }; +