[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 | |
---|
| 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" |
---|
[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 */ |
---|
[944] | 75 | @@ -245,9 +250,67 @@ |
---|
[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", |
---|
[944] | 113 | + "xaml", |
---|
| 114 | + "xap", |
---|
[298] | 115 | + NULL |
---|
| 116 | +}; |
---|
| 117 | + |
---|
| 118 | +static int is_static_extension(const char *file) |
---|
| 119 | +{ |
---|
| 120 | + const char *extension = strrchr(file, '.'); |
---|
| 121 | + const char **p; |
---|
| 122 | + if (extension == NULL) return 0; |
---|
| 123 | + for (p = static_extensions; *p; ++p) { |
---|
| 124 | + if (strcmp(extension + 1, *p) == 0) return 1; |
---|
| 125 | + } |
---|
| 126 | + return 0; |
---|
| 127 | +} |
---|
| 128 | + |
---|
[842] | 129 | +static int is_php_extension(const char *file) |
---|
| 130 | +{ |
---|
| 131 | + const char *extension = strrchr(file, '.'); |
---|
| 132 | + if (extension == NULL) return 0; |
---|
| 133 | + return strcmp(extension + 1, "php") == 0; |
---|
| 134 | +} |
---|
| 135 | + |
---|
[298] | 136 | int main(int argc, char *argv[]) |
---|
| 137 | { |
---|
| 138 | int userdir = 0; /* ~userdir flag */ |
---|
[823] | 139 | + int trusteddir = 0; /* TRUSTED_DIRECTORY flag */ |
---|
| 140 | uid_t uid; /* user information */ |
---|
| 141 | gid_t gid; /* target group placeholder */ |
---|
| 142 | char *target_uname; /* target user name */ |
---|
[1169] | 143 | @@ -268,6 +331,7 @@ |
---|
| 144 | * Start with a "clean" environment |
---|
| 145 | */ |
---|
| 146 | clean_env(); |
---|
| 147 | + setenv("JAVA_TOOL_OPTIONS", "-Xmx128M", 1); /* scripts.mit.edu local hack */ |
---|
[1259] | 148 | |
---|
[1169] | 149 | prog = argv[0]; |
---|
| 150 | /* |
---|
[1259] | 151 | @@ -350,6 +414,20 @@ |
---|
[823] | 152 | #endif /*_OSD_POSIX*/ |
---|
| 153 | |
---|
| 154 | /* |
---|
| 155 | + * First check if this is an absolute path to the directory |
---|
| 156 | + * of trusted executables. These are supposed to be security |
---|
| 157 | + * audited to check parameters and validity on their own... |
---|
| 158 | + */ |
---|
| 159 | + if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) { |
---|
| 160 | + if (strstr(cmd, "/../") != NULL) { |
---|
| 161 | + log_err("invalid command (%s)\n", cmd); |
---|
| 162 | + exit(104); |
---|
| 163 | + } |
---|
| 164 | + trusteddir = 1; |
---|
| 165 | + goto TRUSTED_DIRECTORY; |
---|
| 166 | + } |
---|
| 167 | + |
---|
| 168 | + /* |
---|
| 169 | * Check for a leading '/' (absolute path) in the command to be executed, |
---|
| 170 | * or attempts to back up out of the current directory, |
---|
| 171 | * to protect against attacks. If any are |
---|
[1259] | 172 | @@ -371,6 +449,7 @@ |
---|
[823] | 173 | userdir = 1; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | +TRUSTED_DIRECTORY: |
---|
| 177 | /* |
---|
| 178 | * Error out if the target username is invalid. |
---|
| 179 | */ |
---|
[1259] | 180 | @@ -452,7 +531,7 @@ |
---|
[103] | 181 | * Error out if attempt is made to execute as root or as |
---|
| 182 | * a UID less than AP_UID_MIN. Tsk tsk. |
---|
| 183 | */ |
---|
| 184 | - if ((uid == 0) || (uid < AP_UID_MIN)) { |
---|
| 185 | + if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) { |
---|
| 186 | log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd); |
---|
| 187 | exit(107); |
---|
| 188 | } |
---|
[1259] | 189 | @@ -484,6 +563,21 @@ |
---|
[103] | 190 | log_err("failed to setuid (%ld: %s)\n", uid, cmd); |
---|
| 191 | exit(110); |
---|
| 192 | } |
---|
[406] | 193 | + if (is_selinux_enabled()) { |
---|
| 194 | + if (uid == 102) { |
---|
| 195 | + if (setexeccon("system_u:system_r:signup_t:s0") == -1) { |
---|
| 196 | + log_err("failed to setexeccon (%ld: %s) to signup_t\n", uid, cmd); |
---|
| 197 | + exit(201); |
---|
| 198 | + } |
---|
| 199 | + } else { |
---|
| 200 | + if (setexeccon("user_u:user_r:user_t:s0") == -1) { |
---|
| 201 | + log_err("failed to setexeccon (%ld: %s) to user_t\n", uid, cmd); |
---|
| 202 | + exit(202); |
---|
| 203 | + } |
---|
[405] | 204 | + } |
---|
[103] | 205 | + } |
---|
[908] | 206 | + |
---|
| 207 | + setenv("HOME", target_homedir, 1); |
---|
[103] | 208 | |
---|
| 209 | /* |
---|
| 210 | * Get the current working directory, as well as the proper |
---|
[1259] | 211 | @@ -506,6 +600,21 @@ |
---|
[823] | 212 | log_err("cannot get docroot information (%s)\n", target_homedir); |
---|
| 213 | exit(112); |
---|
[1] | 214 | } |
---|
[823] | 215 | + size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1; |
---|
| 216 | + char *expected = malloc(expected_len); |
---|
| 217 | + snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX); |
---|
| 218 | + if (strncmp(cwd, expected, expected_len-1) != 0) { |
---|
| 219 | + log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected); |
---|
| 220 | + exit(114); |
---|
| 221 | + } |
---|
| 222 | + } |
---|
| 223 | + else if (trusteddir) { |
---|
| 224 | + if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) || |
---|
| 225 | + ((getcwd(dwd, AP_MAXPATH)) == NULL) | |
---|
| 226 | + ((chdir(cwd)) != 0)) { |
---|
| 227 | + log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY); |
---|
| 228 | + exit(112); |
---|
| 229 | + } |
---|
[1] | 230 | } |
---|
[823] | 231 | else { |
---|
| 232 | if (((chdir(AP_DOC_ROOT)) != 0) || |
---|
[1259] | 233 | @@ -532,15 +641,17 @@ |
---|
[1] | 234 | /* |
---|
| 235 | * Error out if cwd is writable by others. |
---|
| 236 | */ |
---|
| 237 | +#if 0 |
---|
| 238 | if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { |
---|
| 239 | log_err("directory is writable by others: (%s)\n", cwd); |
---|
| 240 | exit(116); |
---|
| 241 | } |
---|
| 242 | +#endif |
---|
| 243 | |
---|
| 244 | /* |
---|
| 245 | * Error out if we cannot stat the program. |
---|
| 246 | */ |
---|
| 247 | - if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { |
---|
| 248 | + if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) { |
---|
| 249 | log_err("cannot stat program: (%s)\n", cmd); |
---|
| 250 | exit(117); |
---|
| 251 | } |
---|
[1259] | 252 | @@ -548,10 +659,12 @@ |
---|
[1] | 253 | /* |
---|
| 254 | * Error out if the program is writable by others. |
---|
| 255 | */ |
---|
| 256 | +#if 0 |
---|
| 257 | if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { |
---|
| 258 | log_err("file is writable by others: (%s/%s)\n", cwd, cmd); |
---|
| 259 | exit(118); |
---|
| 260 | } |
---|
| 261 | +#endif |
---|
| 262 | |
---|
| 263 | /* |
---|
| 264 | * Error out if the file is setuid or setgid. |
---|
[1259] | 265 | @@ -565,6 +678,7 @@ |
---|
[1] | 266 | * Error out if the target name/group is different from |
---|
| 267 | * the name/group of the cwd or the program. |
---|
| 268 | */ |
---|
| 269 | +#if 0 |
---|
| 270 | if ((uid != dir_info.st_uid) || |
---|
| 271 | (gid != dir_info.st_gid) || |
---|
| 272 | (uid != prg_info.st_uid) || |
---|
[1259] | 273 | @@ -576,16 +690,33 @@ |
---|
[1] | 274 | prg_info.st_uid, prg_info.st_gid); |
---|
| 275 | exit(120); |
---|
| 276 | } |
---|
| 277 | +#endif |
---|
| 278 | /* |
---|
| 279 | * Error out if the program is not executable for the user. |
---|
| 280 | * Otherwise, she won't find any error in the logs except for |
---|
[842] | 281 | * "[error] Premature end of script headers: ..." |
---|
| 282 | */ |
---|
| 283 | - if (!(prg_info.st_mode & S_IXUSR)) { |
---|
| 284 | + if (!is_static_extension(cmd) && !is_php_extension(cmd) && |
---|
[873] | 285 | + !(prg_info.st_mode & S_IXUSR)) { |
---|
[842] | 286 | log_err("file has no execute permission: (%s/%s)\n", cwd, cmd); |
---|
[873] | 287 | exit(121); |
---|
[842] | 288 | } |
---|
[298] | 289 | |
---|
| 290 | + if (is_static_extension(cmd)) { |
---|
| 291 | + argv[2] = STATIC_CAT_PATH; |
---|
| 292 | + execv(STATIC_CAT_PATH, &argv[2]); |
---|
[1259] | 293 | + log_err("(%d)%s: static_cat exec failed (%s)\n", errno, strerror(errno), argv[2]); |
---|
| 294 | + exit(255); |
---|
[298] | 295 | + } |
---|
[842] | 296 | + if (is_php_extension(cmd)) { |
---|
| 297 | + setenv("PHPRC", ".", 1); |
---|
| 298 | + argv[1] = PHP_PATH; |
---|
| 299 | + argv[2] = "-f"; |
---|
| 300 | + execv(PHP_PATH, &argv[1]); |
---|
[1354] | 301 | + log_err("(%d)%s: php exec failed (%s)\n", errno, strerror(errno), argv[1]); |
---|
[1259] | 302 | + exit(255); |
---|
[842] | 303 | + } |
---|
[298] | 304 | + |
---|
[1259] | 305 | #ifdef AP_SUEXEC_UMASK |
---|
[298] | 306 | /* |
---|
[1259] | 307 | * umask() uses inverse logic; bits are CLEAR for allowed access. |
---|