source: server/common/patches/httpd-suexec-scripts.patch @ 848

Last change on this file since 848 was 842, checked in by andersk, 16 years ago
Run php directly from suexec, so php scripts don’t need to be executable.
File size: 8.9 KB
RevLine 
[1]1# scripts.mit.edu httpd suexec patch
[823]2# Copyright (C) 2006, 2007, 2008  Jeff Arnold <jbarnold@mit.edu>,
3#                                 Joe Presbrey <presbrey@mit.edu>,
4#                                 Anders Kaseorg <andersk@mit.edu>,
5#                                 Geoffrey Thomas <geofft@mit.edu>
[1]6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License
9# as published by the Free Software Foundation; either version 2
10# of the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20#
21# See /COPYRIGHT in this repository for more information.
22#
[103]23--- httpd-2.2.2/support/Makefile.in.old 2005-07-06 19:15:34.000000000 -0400
24+++ httpd-2.2.2/support/Makefile.in     2007-01-20 17:12:51.000000000 -0500
25@@ -60,7 +60,7 @@
26
27 suexec_OBJECTS = suexec.lo
28 suexec: $(suexec_OBJECTS)
29-       $(LINK) $(suexec_OBJECTS)
30+       $(LINK) -lselinux $(suexec_OBJECTS)
31
32 htcacheclean_OBJECTS = htcacheclean.lo
33 htcacheclean: $(htcacheclean_OBJECTS)
[823]34--- httpd-2.2.2/configure.in.old        2007-07-17 10:48:25.000000000 -0400
35+++ httpd-2.2.2/configure.in    2008-08-29 08:15:41.000000000 -0400
36@@ -559,6 +559,10 @@
37 APACHE_HELP_STRING(--with-suexec-userdir,User subdirectory),[
38   AC_DEFINE_UNQUOTED(AP_USERDIR_SUFFIX, "$withval", [User subdirectory] ) ] )
39 
40+AC_ARG_WITH(suexec-trusteddir,
41+APACHE_HELP_STRING(--with-suexec-trusteddir,Trusted SuExec directory),[
42+  AC_DEFINE_UNQUOTED(AP_TRUSTED_DIRECTORY, "$withval", [Trusted SuExec directory] ) ] )
43+
44 AC_ARG_WITH(suexec-docroot,
45 APACHE_HELP_STRING(--with-suexec-docroot,SuExec root directory),[
46   AC_DEFINE_UNQUOTED(AP_DOC_ROOT, "$withval", [SuExec root directory] ) ] )
[1]47--- httpd-2.2.2/support/suexec.c.old    2006-04-21 21:53:06.000000000 -0400
[315]48+++ httpd-2.2.2/support/suexec.c        2007-05-22 10:32:04.000000000 -0400
[842]49@@ -30,6 +30,9 @@
[298]50  *
51  */
52 
53+#define STATIC_CAT_PATH "/usr/local/bin/static-cat"
[842]54+#define PHP_PATH "/usr/bin/php-cgi"
[298]55+
56 #include "apr.h"
57 #include "ap_config.h"
58 #include "suexec.h"
59@@ -46,6 +48,7 @@
[103]60 #include <stdio.h>
61 #include <stdarg.h>
62 #include <stdlib.h>
63+#include <selinux/selinux.h>
64 
65 #ifdef HAVE_PWD_H
66 #include <pwd.h>
[405]67@@ -95,6 +98,7 @@
[1]68 {
69     /* variable name starts with */
70     "HTTP_",
71+    "HTTPS_",
72     "SSL_",
73 
74     /* variable name is */
[842]75@@ -245,9 +250,65 @@
[298]76     environ = cleanenv;
77 }
78 
79+static const char *static_extensions[] = {
80+    "html",
81+    "css",
82+    "gif",
83+    "jpg",
84+    "png",
85+    "htm",
86+    "jpeg",
87+    "js",
88+    "ico",
89+    "xml",
90+    "xsl",
91+    "tiff",
92+    "tif",
93+    "tgz",
94+    "tar",
95+    "jar",
96+    "zip",
97+    "pdf",
98+    "ps",
99+    "doc",
100+    "xls",
101+    "ppt",
102+    "swf",
103+    "mp3",
104+    "mov",
105+    "wmv",
106+    "mpg",
107+    "mpeg",
108+    "avi",
109+    "il",
110+    "JPG",
[315]111+    "xhtml",
[618]112+    "svg",
[298]113+    NULL
114+};
115+
116+static int is_static_extension(const char *file)
117+{
118+    const char *extension = strrchr(file, '.');
119+    const char **p;
120+    if (extension == NULL) return 0;
121+    for (p = static_extensions; *p; ++p) {
122+        if (strcmp(extension + 1, *p) == 0) return 1;
123+    }
124+    return 0;
125+}
126+
[842]127+static int is_php_extension(const char *file)
128+{
129+    const char *extension = strrchr(file, '.');
130+    if (extension == NULL) return 0;
131+    return strcmp(extension + 1, "php") == 0;
132+}
133+
[298]134 int main(int argc, char *argv[])
135 {
136     int userdir = 0;        /* ~userdir flag             */
[823]137+    int trusteddir = 0;     /* TRUSTED_DIRECTORY flag    */
138     uid_t uid;              /* user information          */
139     gid_t gid;              /* target group placeholder  */
140     char *target_uname;     /* target user name          */
141@@ -350,6 +404,20 @@
142 #endif /*_OSD_POSIX*/
143 
144     /*
145+     * First check if this is an absolute path to the directory
146+     * of trusted executables. These are supposed to be security
147+     * audited to check parameters and validity on their own...
148+     */
149+    if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) {
150+        if (strstr(cmd, "/../") != NULL) {
151+            log_err("invalid command (%s)\n", cmd);
152+            exit(104);
153+        }
154+        trusteddir = 1;
155+        goto TRUSTED_DIRECTORY;
156+    }
157+
158+    /*
159      * Check for a leading '/' (absolute path) in the command to be executed,
160      * or attempts to back up out of the current directory,
161      * to protect against attacks.  If any are
162@@ -371,6 +439,7 @@
163         userdir = 1;
164     }
165 
166+TRUSTED_DIRECTORY:
167     /*
168      * Error out if the target username is invalid.
169      */
170@@ -450,7 +519,7 @@
[103]171      * Error out if attempt is made to execute as root or as
172      * a UID less than AP_UID_MIN.  Tsk tsk.
173      */
174-    if ((uid == 0) || (uid < AP_UID_MIN)) {
175+    if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) {
176         log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd);
177         exit(107);
178     }
[823]179@@ -482,6 +551,19 @@
[103]180         log_err("failed to setuid (%ld: %s)\n", uid, cmd);
181         exit(110);
182     }
[406]183+    if (is_selinux_enabled()) {
184+        if (uid == 102) {
185+            if (setexeccon("system_u:system_r:signup_t:s0") == -1) {
186+                log_err("failed to setexeccon (%ld: %s) to signup_t\n", uid, cmd);
187+                exit(201);
188+            }
189+        } else {
190+            if (setexeccon("user_u:user_r:user_t:s0") == -1) {
191+                log_err("failed to setexeccon (%ld: %s) to user_t\n", uid, cmd);
192+                exit(202);
193+            }
[405]194+        }
[103]195+    }
196 
197     /*
198      * Get the current working directory, as well as the proper
[823]199@@ -504,6 +586,21 @@
200             log_err("cannot get docroot information (%s)\n", target_homedir);
201             exit(112);
[1]202         }
[823]203+        size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1;
204+        char *expected = malloc(expected_len);
205+        snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX);
206+        if (strncmp(cwd, expected, expected_len-1) != 0) {
207+            log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected);
208+            exit(114);
209+        }
210+    }
211+    else if (trusteddir) {
212+        if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) ||
213+            ((getcwd(dwd, AP_MAXPATH)) == NULL) |
214+            ((chdir(cwd)) != 0)) {
215+            log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY);
216+            exit(112);
217+        }
[1]218     }
[823]219     else {
220         if (((chdir(AP_DOC_ROOT)) != 0) ||
221@@ -530,15 +627,17 @@
[1]222     /*
223      * Error out if cwd is writable by others.
224      */
225+#if 0
226     if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
227         log_err("directory is writable by others: (%s)\n", cwd);
228         exit(116);
229     }
230+#endif
231 
232     /*
233      * Error out if we cannot stat the program.
234      */
235-    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
236+    if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) {
237         log_err("cannot stat program: (%s)\n", cmd);
238         exit(117);
239     }
[823]240@@ -546,10 +645,12 @@
[1]241     /*
242      * Error out if the program is writable by others.
243      */
244+#if 0
245     if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
246         log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
247         exit(118);
248     }
249+#endif
250 
251     /*
252      * Error out if the file is setuid or setgid.
[823]253@@ -563,6 +664,7 @@
[1]254      * Error out if the target name/group is different from
255      * the name/group of the cwd or the program.
256      */
257+#if 0
258     if ((uid != dir_info.st_uid) ||
259         (gid != dir_info.st_gid) ||
260         (uid != prg_info.st_uid) ||
[842]261@@ -574,12 +676,14 @@
[1]262                 prg_info.st_uid, prg_info.st_gid);
263         exit(120);
264     }
265+#endif
266     /*
267      * Error out if the program is not executable for the user.
268      * Otherwise, she won't find any error in the logs except for
[842]269      * "[error] Premature end of script headers: ..."
270      */
271-    if (!(prg_info.st_mode & S_IXUSR)) {
272+    if (!is_static_extension(cmd) && !is_php_extension(cmd) &&
273+        !(prg_info.st_mode & S_IXUSR)) {
274         log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
275         exit(121);
276     }
277@@ -606,6 +709,21 @@
[823]278       exit(122);
[298]279     }
280 
281+    if (is_static_extension(cmd)) {
282+        argv[2] = STATIC_CAT_PATH;
283+        execv(STATIC_CAT_PATH, &argv[2]);
284+       log_err("(%d)%s: static_cat exec failed (%s)\n", errno, strerror(errno), argv[2]);
285+       exit(255);
286+    }
[842]287+    if (is_php_extension(cmd)) {
288+        setenv("PHPRC", ".", 1);
289+        argv[1] = PHP_PATH;
290+        argv[2] = "-f";
291+        execv(PHP_PATH, &argv[1]);
292+       log_err("(%d)%s: php exec failed (%s)\n", errno, strerror(errno), argv[2]);
293+       exit(255);
294+    }
[298]295+
296     /*
297      * Execute the command, replacing our image with its own.
298      */
Note: See TracBrowser for help on using the repository browser.