1
#! /bin/sh /usr/share/dpatch/dpatch-run
2
## 04_CVE-2008-1614.dpatch
4
## All lines beginning with `## DP:' are a description of the patch.
5
## DP: Fix for CVE-2008-1614 - race condition in symlink handling
8
--- suphp-0.6.2.orig/src/API_Linux.hpp
9
+++ suphp-0.6.2/src/API_Linux.hpp
11
virtual GroupInfo File_getGroup(const File& file) const
12
throw (SystemException);
15
+ * Checks whether a file is a symlink
17
+ virtual bool File_isSymlink(const File& file) const throw (SystemException);
20
* Runs another program (replaces current process)
24
--- suphp-0.6.2.orig/src/File.cpp
25
+++ suphp-0.6.2/src/File.cpp
27
File suPHP::File::getParentDirectory() const {
28
std::string path = this->getPath();
29
path = path.substr(0, path.rfind('/'));
30
+ if (path.length() == 0) {
37
GroupInfo suPHP::File::getGroup() const throw (SystemException) {
38
return API_Helper::getSystemAPI().File_getGroup(*this);
41
+bool suPHP::File::isSymlink() const throw (SystemException) {
42
+ return API_Helper::getSystemAPI().File_isSymlink(*this);
46
--- suphp-0.6.2.orig/src/Application.hpp
47
+++ suphp-0.6.2/src/Application.hpp
49
const Configuration& config) const
50
throw (SoftException);
54
+ * Checks ownership and permissions for parent directories
56
+ void checkParentDirectories(const File& file,
57
+ const UserInfo& owner,
58
+ const Configuration& config) const
59
+ throw (SoftException);
65
--- suphp-0.6.2.orig/src/Application.cpp
66
+++ suphp-0.6.2/src/Application.cpp
68
throw (SystemException, SoftException) {
69
Logger& logger = API_Helper::getSystemAPI().getSystemLogger();
70
File scriptFile = File(scriptFilename);
71
+ File realScriptFile = File(scriptFile.getRealPath());
73
// Check wheter file exists
74
if (!scriptFile.exists()) {
76
logger.logWarning(error);
77
throw SoftException(error, __FILE__, __LINE__);
80
- // Get full path to script file
82
- File realScriptFile = File(scriptFile.getRealPath());
83
- File directory = realScriptFile.getParentDirectory();
84
+ if (!realScriptFile.exists()) {
85
+ std::string error = "File " + realScriptFile.getPath()
86
+ + " referenced by symlink " +scriptFile.getPath()
87
+ + " does not exist";
88
+ logger.logWarning(error);
89
+ throw SoftException(error, __FILE__, __LINE__);
92
// Check wheter script is in docroot
93
if (realScriptFile.getPath().find(config.getDocroot()) != 0) {
95
logger.logWarning(error);
96
throw SoftException(error, __FILE__, __LINE__);
98
+ if (config.getCheckVHostDocroot()
99
+ && scriptFile.getPath().find(environment.getVar("DOCUMENT_ROOT"))
102
+ std::string error = "File \"" + scriptFile.getPath()
103
+ + "\" is not in document root of Vhost \""
104
+ + environment.getVar("DOCUMENT_ROOT") + "\"";
105
+ logger.logWarning(error);
106
+ throw SoftException(error, __FILE__, __LINE__);
109
- // Check script and directory permissions
110
+ // Check script permissions
111
+ // Directories will be checked later
112
if (!realScriptFile.hasUserReadBit()) {
113
std::string error = "File \"" + realScriptFile.getPath()
116
throw SoftException(error, __FILE__, __LINE__);
119
- if (!config.getAllowDirectoryGroupWriteable()
120
- && directory.hasGroupWriteBit()) {
121
- std::string error = "Directory \"" + directory.getPath()
122
- + "\" is writeable by group";
123
- logger.logWarning(error);
124
- throw SoftException(error, __FILE__, __LINE__);
127
if (!config.getAllowFileOthersWriteable()
128
&& realScriptFile.hasOthersWriteBit()) {
129
std::string error = "File \"" + realScriptFile.getPath()
131
throw SoftException(error, __FILE__, __LINE__);
134
- if (!config.getAllowDirectoryOthersWriteable()
135
- && directory.hasOthersWriteBit()) {
136
- std::string error = "Directory \"" + directory.getPath()
137
- + "\" is writeable by others";
138
- logger.logWarning(error);
139
- throw SoftException(error, __FILE__, __LINE__);
142
// Check UID/GID of symlink is matching target
143
if (scriptFile.getUser() != realScriptFile.getUser()
144
|| scriptFile.getGroup() != realScriptFile.getGroup()) {
147
GroupInfo targetGroup;
149
- File scriptFile = File(File(scriptFilename).getRealPath());
150
+ File scriptFile = File(scriptFilename);
151
+ File realScriptFile = File(scriptFile.getRealPath());
152
API& api = API_Helper::getSystemAPI();
153
Logger& logger = api.getSystemLogger();
156
throw SoftException(error, __FILE__, __LINE__);
158
#endif // OPT_USERGROUP_PARANOID
161
+ // Check directory ownership and permissions
162
+ checkParentDirectories(realScriptFile, targetUser, config);
163
+ checkParentDirectories(scriptFile, targetUser, config);
165
// Common code used for all modes
167
// Set new group first, because we still need super-user privileges
172
+void suPHP::Application::checkParentDirectories(const File& file,
173
+ const UserInfo& owner,
174
+ const Configuration& config) const throw (SoftException) {
175
+ File directory = file;
176
+ Logger& logger = API_Helper::getSystemAPI().getSystemLogger();
178
+ directory = directory.getParentDirectory();
180
+ UserInfo directoryOwner = directory.getUser();
181
+ if (directoryOwner != owner && !directoryOwner.isSuperUser()) {
182
+ std::string error = "Directory " + directory.getPath()
183
+ + " is not owned by " + owner.getUsername();
184
+ logger.logWarning(error);
185
+ throw SoftException(error, __FILE__, __LINE__);
188
+ if (!directory.isSymlink()
189
+ && !config.getAllowDirectoryGroupWriteable()
190
+ && directory.hasGroupWriteBit()) {
191
+ std::string error = "Directory \"" + directory.getPath()
192
+ + "\" is writeable by group";
193
+ logger.logWarning(error);
194
+ throw SoftException(error, __FILE__, __LINE__);
197
+ if (!directory.isSymlink()
198
+ && !config.getAllowDirectoryOthersWriteable()
199
+ && directory.hasOthersWriteBit()) {
200
+ std::string error = "Directory \"" + directory.getPath()
201
+ + "\" is writeable by others";
202
+ logger.logWarning(error);
203
+ throw SoftException(error, __FILE__, __LINE__);
205
+ } while (directory.getPath() != "/");
209
int main(int argc, char **argv) {
211
API& api = API_Helper::getSystemAPI();
214
--- suphp-0.6.2.orig/src/API_Linux.cpp
215
+++ suphp-0.6.2/src/API_Linux.cpp
216
@@ -225,10 +225,10 @@
218
bool suPHP::API_Linux::File_exists(const File& file) const {
220
- if (::stat(file.getPath().c_str(), &dummy) == 0)
222
+ if (::lstat(file.getPath().c_str(), &dummy) == 0)
229
std::string suPHP::API_Linux::File_getRealPath(const File& file) const
231
bool suPHP::API_Linux::File_hasPermissionBit(const File& file, FileMode perm)
232
const throw (SystemException) {
234
- if (stat(file.getPath().c_str(), &temp) == -1) {
235
+ if (lstat(file.getPath().c_str(), &temp) == -1) {
236
throw SystemException(std::string("Could not stat \"")
237
+ file.getPath() + "\": "
238
+ ::strerror(errno), __FILE__, __LINE__);
240
UserInfo suPHP::API_Linux::File_getUser(const File& file) const
241
throw (SystemException) {
243
- if (stat(file.getPath().c_str(), &temp) == -1) {
244
+ if (lstat(file.getPath().c_str(), &temp) == -1) {
245
throw SystemException(std::string("Could not stat \"")
246
+ file.getPath() + "\": "
247
+ ::strerror(errno), __FILE__, __LINE__);
249
GroupInfo suPHP::API_Linux::File_getGroup(const File& file) const
250
throw (SystemException) {
252
- if (stat(file.getPath().c_str(), &temp) == -1) {
253
+ if (lstat(file.getPath().c_str(), &temp) == -1) {
254
throw SystemException(std::string("Could not stat \"")
255
+ file.getPath() + "\": "
256
+ ::strerror(errno), __FILE__, __LINE__);
261
+bool suPHP::API_Linux::File_isSymlink(const File& file) const throw (SystemException) {
262
+ return this->isSymlink(file.getPath());
266
void suPHP::API_Linux::execute(std::string program, const CommandLine& cline,
267
const Environment& env) const
268
throw (SystemException) {
271
--- suphp-0.6.2.orig/src/File.hpp
272
+++ suphp-0.6.2/src/File.hpp
274
* Returns owning group of file
276
GroupInfo getGroup() const throw (SystemException);
280
+ * Checks whether this file is a symlink
282
+ bool isSymlink() const throw (SystemException);
288
--- suphp-0.6.2.orig/src/API.hpp
289
+++ suphp-0.6.2/src/API.hpp
291
virtual GroupInfo File_getGroup(const File& file) const
292
throw (SystemException) =0;
295
+ * Checks whether a file is a symlink
297
+ virtual bool File_isSymlink(const File& file) const
298
+ throw (SystemException) =0;
301
* Runs another program (replaces current process)