source: branches/fc17-dev/server/common/patches/httpd-suexec-scripts.patch @ 2195

Last change on this file since 2195 was 2195, checked in by ezyang, 10 years ago
Merge changes from trunk.
File size: 9.8 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] ) ] )
[1259]47--- httpd-2.2.11/support/suexec.c.old   2008-11-30 10:47:31.000000000 -0500
48+++ httpd-2.2.11/support/suexec.c       2009-06-08 09:02:17.000000000 -0400
[842]49@@ -30,6 +30,9 @@
[298]50  *
51  */
52 
[1590]53+#define STATIC_CAT_PATH "/usr/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"
[1259]59@@ -46,6 +49,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>
[1259]67@@ -95,6 +99,7 @@
[1]68 {
69     /* variable name starts with */
70     "HTTP_",
71+    "HTTPS_",
72     "SSL_",
73 
74     /* variable name is */
[1877]75@@ -245,9 +250,108 @@
[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",
[1877]102+    "dot",
103+    "docx",
104+    "dotx",
105+    "docm",
106+    "dotm",
107+    "xlt",
108+    "xla",
109+    "xlsx",
110+    "xltx",
111+    "xlsm",
112+    "xltm",
113+    "xlam",
114+    "xlsb",
115+    "pot",
116+    "pps",
117+    "ppa",
118+    "pptx",
119+    "potx",
120+    "ppsx",
121+    "ppam",
122+    "pptm",
123+    "potm",
124+    "ppsm",
[298]125+    "swf",
126+    "mp3",
127+    "mov",
128+    "wmv",
129+    "mpg",
130+    "mpeg",
131+    "avi",
132+    "il",
[315]133+    "xhtml",
[618]134+    "svg",
[944]135+    "xaml",
136+    "xap",
[1464]137+    "wav",
138+    "mid",
139+    "midi",
[1785]140+    "ttf",
141+    "otf",
[1877]142+    "odc",
143+    "odb",
144+    "odf",
145+    "odg",
146+    "otg",
147+    "odi",
148+    "odp",
149+    "otp",
150+    "ods",
151+    "ots",
152+    "odt",
153+    "odm",
154+    "ott",
155+    "oth",
[298]156+    NULL
157+};
158+
159+static int is_static_extension(const char *file)
160+{
161+    const char *extension = strrchr(file, '.');
162+    const char **p;
163+    if (extension == NULL) return 0;
164+    for (p = static_extensions; *p; ++p) {
[1464]165+        if (strcasecmp(extension + 1, *p) == 0) return 1;
[298]166+    }
167+    return 0;
168+}
169+
[842]170+static int is_php_extension(const char *file)
171+{
172+    const char *extension = strrchr(file, '.');
173+    if (extension == NULL) return 0;
174+    return strcmp(extension + 1, "php") == 0;
175+}
176+
[298]177 int main(int argc, char *argv[])
178 {
179     int userdir = 0;        /* ~userdir flag             */
[823]180+    int trusteddir = 0;     /* TRUSTED_DIRECTORY flag    */
181     uid_t uid;              /* user information          */
182     gid_t gid;              /* target group placeholder  */
183     char *target_uname;     /* target user name          */
[1877]184@@ -268,6 +368,7 @@
[1169]185      * Start with a "clean" environment
186      */
187     clean_env();
188+    setenv("JAVA_TOOL_OPTIONS", "-Xmx128M", 1); /* scripts.mit.edu local hack */
[1259]189 
[1169]190     prog = argv[0];
191     /*
[1877]192@@ -350,6 +451,20 @@
[823]193 #endif /*_OSD_POSIX*/
194 
195     /*
196+     * First check if this is an absolute path to the directory
197+     * of trusted executables. These are supposed to be security
198+     * audited to check parameters and validity on their own...
199+     */
200+    if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) {
201+        if (strstr(cmd, "/../") != NULL) {
202+            log_err("invalid command (%s)\n", cmd);
203+            exit(104);
204+        }
205+        trusteddir = 1;
206+        goto TRUSTED_DIRECTORY;
207+    }
208+
209+    /*
210      * Check for a leading '/' (absolute path) in the command to be executed,
211      * or attempts to back up out of the current directory,
212      * to protect against attacks.  If any are
[1877]213@@ -371,6 +486,7 @@
[823]214         userdir = 1;
215     }
216 
217+TRUSTED_DIRECTORY:
218     /*
219      * Error out if the target username is invalid.
220      */
[1877]221@@ -452,7 +568,7 @@
[103]222      * Error out if attempt is made to execute as root or as
223      * a UID less than AP_UID_MIN.  Tsk tsk.
224      */
225-    if ((uid == 0) || (uid < AP_UID_MIN)) {
[1474]226+    if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) { /* uid 102 = signup  */
[103]227         log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd);
228         exit(107);
229     }
[1877]230@@ -484,6 +599,7 @@
[103]231         log_err("failed to setuid (%ld: %s)\n", uid, cmd);
232         exit(110);
233     }
[908]234+    setenv("HOME", target_homedir, 1);
[103]235 
236     /*
237      * Get the current working directory, as well as the proper
[1877]238@@ -506,6 +637,21 @@
[823]239             log_err("cannot get docroot information (%s)\n", target_homedir);
240             exit(112);
[1]241         }
[823]242+        size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1;
243+        char *expected = malloc(expected_len);
244+        snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX);
245+        if (strncmp(cwd, expected, expected_len-1) != 0) {
246+            log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected);
247+            exit(114);
248+        }
249+    }
250+    else if (trusteddir) {
251+        if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) ||
252+            ((getcwd(dwd, AP_MAXPATH)) == NULL) |
253+            ((chdir(cwd)) != 0)) {
254+            log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY);
255+            exit(112);
256+        }
[1]257     }
[823]258     else {
259         if (((chdir(AP_DOC_ROOT)) != 0) ||
[1877]260@@ -532,15 +678,17 @@
[1]261     /*
262      * Error out if cwd is writable by others.
263      */
264+#if 0
265     if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
266         log_err("directory is writable by others: (%s)\n", cwd);
267         exit(116);
268     }
269+#endif
270 
271     /*
272      * Error out if we cannot stat the program.
273      */
274-    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
275+    if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) {
276         log_err("cannot stat program: (%s)\n", cmd);
277         exit(117);
278     }
[1877]279@@ -548,10 +696,12 @@
[1]280     /*
281      * Error out if the program is writable by others.
282      */
283+#if 0
284     if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
285         log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
286         exit(118);
287     }
288+#endif
289 
290     /*
291      * Error out if the file is setuid or setgid.
[1877]292@@ -565,6 +715,7 @@
[1]293      * Error out if the target name/group is different from
294      * the name/group of the cwd or the program.
295      */
296+#if 0
297     if ((uid != dir_info.st_uid) ||
298         (gid != dir_info.st_gid) ||
299         (uid != prg_info.st_uid) ||
[1877]300@@ -576,12 +727,14 @@
[1]301                 prg_info.st_uid, prg_info.st_gid);
302         exit(120);
303     }
304+#endif
305     /*
306      * Error out if the program is not executable for the user.
307      * Otherwise, she won't find any error in the logs except for
[842]308      * "[error] Premature end of script headers: ..."
309      */
310-    if (!(prg_info.st_mode & S_IXUSR)) {
311+    if (!is_static_extension(cmd) && !is_php_extension(cmd) &&
[873]312+        !(prg_info.st_mode & S_IXUSR)) {
[842]313         log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
[873]314         exit(121);
[842]315     }
[2195]316@@ -614,6 +767,30 @@
[1355]317     /*
318      * Execute the command, replacing our image with its own.
319      */
[298]320+    if (is_static_extension(cmd)) {
[1590]321+        if (setenv("PATH_TRANSLATED", cmd, 1) != 0) {
322+            log_err("setenv failed\n");
323+            exit(255);
324+        }
325+        execl(STATIC_CAT_PATH, STATIC_CAT_PATH, (const char *)NULL);
326+        log_err("(%d)%s: static-cat exec failed (%s)\n", errno, strerror(errno), STATIC_CAT_PATH);
[1259]327+        exit(255);
[298]328+    }
[842]329+    if (is_php_extension(cmd)) {
330+        setenv("PHPRC", ".", 1);
331+        argv[1] = PHP_PATH;
332+        argv[2] = "-f";
[2195]333+        /*
334+         * argv[3] is the command to run. argv[4] is either an argument or
335+         * already null. We don't want to pass any arguments through from
336+         * Apache (since they're untrusted), so we chop off the remainder
337+         * of argv here.
338+         */
339+        argv[4] = 0;
[842]340+        execv(PHP_PATH, &argv[1]);
[1354]341+        log_err("(%d)%s: php exec failed (%s)\n", errno, strerror(errno), argv[1]);
[1259]342+        exit(255);
[842]343+    }
[1355]344 #ifdef NEED_HASHBANG_EMUL
345     /* We need the #! emulation when we want to execute scripts */
346     {
Note: See TracBrowser for help on using the repository browser.