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

Last change on this file since 2332 was 2186, checked in by ezyang, 13 years ago
Another mitigation to the PHP command line flags vulnerability.
File size: 9.8 KB
  • httpd-2.2.2/support/Makefile.in

    # scripts.mit.edu httpd suexec patch
    # Copyright (C) 2006, 2007, 2008  Jeff Arnold <jbarnold@mit.edu>,
    #                                 Joe Presbrey <presbrey@mit.edu>,
    #                                 Anders Kaseorg <andersk@mit.edu>,
    #                                 Geoffrey Thomas <geofft@mit.edu>
    #
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU General Public License
    # as published by the Free Software Foundation; either version 2
    # of the License, or (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
    #
    # See /COPYRIGHT in this repository for more information.
    #
    old new  
    6060
    6161suexec_OBJECTS = suexec.lo
    6262suexec: $(suexec_OBJECTS)
    63         $(LINK) $(suexec_OBJECTS)
     63        $(LINK) -lselinux $(suexec_OBJECTS)
    6464
    6565htcacheclean_OBJECTS = htcacheclean.lo
    6666htcacheclean: $(htcacheclean_OBJECTS)
  • httpd-2.2.2/configure.in

    old new  
    559559APACHE_HELP_STRING(--with-suexec-userdir,User subdirectory),[
    560560  AC_DEFINE_UNQUOTED(AP_USERDIR_SUFFIX, "$withval", [User subdirectory] ) ] )
    561561
     562AC_ARG_WITH(suexec-trusteddir,
     563APACHE_HELP_STRING(--with-suexec-trusteddir,Trusted SuExec directory),[
     564  AC_DEFINE_UNQUOTED(AP_TRUSTED_DIRECTORY, "$withval", [Trusted SuExec directory] ) ] )
     565
    562566AC_ARG_WITH(suexec-docroot,
    563567APACHE_HELP_STRING(--with-suexec-docroot,SuExec root directory),[
    564568  AC_DEFINE_UNQUOTED(AP_DOC_ROOT, "$withval", [SuExec root directory] ) ] )
  • httpd-2.2.11/support/suexec.c

    old new  
    3030 *
    3131 */
    3232
     33#define STATIC_CAT_PATH "/usr/bin/static-cat"
     34#define PHP_PATH "/usr/bin/php-cgi"
     35
    3336#include "apr.h"
    3437#include "ap_config.h"
    3538#include "suexec.h"
     
    4649#include <stdio.h>
    4750#include <stdarg.h>
    4851#include <stdlib.h>
     52#include <selinux/selinux.h>
    4953
    5054#ifdef HAVE_PWD_H
    5155#include <pwd.h>
     
    9599{
    96100    /* variable name starts with */
    97101    "HTTP_",
     102    "HTTPS_",
    98103    "SSL_",
    99104
    100105    /* variable name is */
     
    245250    environ = cleanenv;
    246251}
    247252
     253static const char *static_extensions[] = {
     254    "html",
     255    "css",
     256    "gif",
     257    "jpg",
     258    "png",
     259    "htm",
     260    "jpeg",
     261    "js",
     262    "ico",
     263    "xml",
     264    "xsl",
     265    "tiff",
     266    "tif",
     267    "tgz",
     268    "tar",
     269    "jar",
     270    "zip",
     271    "pdf",
     272    "ps",
     273    "doc",
     274    "xls",
     275    "ppt",
     276    "dot",
     277    "docx",
     278    "dotx",
     279    "docm",
     280    "dotm",
     281    "xlt",
     282    "xla",
     283    "xlsx",
     284    "xltx",
     285    "xlsm",
     286    "xltm",
     287    "xlam",
     288    "xlsb",
     289    "pot",
     290    "pps",
     291    "ppa",
     292    "pptx",
     293    "potx",
     294    "ppsx",
     295    "ppam",
     296    "pptm",
     297    "potm",
     298    "ppsm",
     299    "swf",
     300    "mp3",
     301    "mov",
     302    "wmv",
     303    "mpg",
     304    "mpeg",
     305    "avi",
     306    "il",
     307    "xhtml",
     308    "svg",
     309    "xaml",
     310    "xap",
     311    "wav",
     312    "mid",
     313    "midi",
     314    "ttf",
     315    "otf",
     316    "odc",
     317    "odb",
     318    "odf",
     319    "odg",
     320    "otg",
     321    "odi",
     322    "odp",
     323    "otp",
     324    "ods",
     325    "ots",
     326    "odt",
     327    "odm",
     328    "ott",
     329    "oth",
     330    NULL
     331};
     332
     333static int is_static_extension(const char *file)
     334{
     335    const char *extension = strrchr(file, '.');
     336    const char **p;
     337    if (extension == NULL) return 0;
     338    for (p = static_extensions; *p; ++p) {
     339        if (strcasecmp(extension + 1, *p) == 0) return 1;
     340    }
     341    return 0;
     342}
     343
     344static int is_php_extension(const char *file)
     345{
     346    const char *extension = strrchr(file, '.');
     347    if (extension == NULL) return 0;
     348    return strcmp(extension + 1, "php") == 0;
     349}
     350
    248351int main(int argc, char *argv[])
    249352{
    250353    int userdir = 0;        /* ~userdir flag             */
     354    int trusteddir = 0;     /* TRUSTED_DIRECTORY flag    */
    251355    uid_t uid;              /* user information          */
    252356    gid_t gid;              /* target group placeholder  */
    253357    char *target_uname;     /* target user name          */
     
    268368     * Start with a "clean" environment
    269369     */
    270370    clean_env();
     371    setenv("JAVA_TOOL_OPTIONS", "-Xmx128M", 1); /* scripts.mit.edu local hack */
    271372
    272373    prog = argv[0];
    273374    /*
     
    350451#endif /*_OSD_POSIX*/
    351452
    352453    /*
     454     * First check if this is an absolute path to the directory
     455     * of trusted executables. These are supposed to be security
     456     * audited to check parameters and validity on their own...
     457     */
     458    if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) {
     459        if (strstr(cmd, "/../") != NULL) {
     460            log_err("invalid command (%s)\n", cmd);
     461            exit(104);
     462        }
     463        trusteddir = 1;
     464        goto TRUSTED_DIRECTORY;
     465    }
     466
     467    /*
    353468     * Check for a leading '/' (absolute path) in the command to be executed,
    354469     * or attempts to back up out of the current directory,
    355470     * to protect against attacks.  If any are
     
    371486        userdir = 1;
    372487    }
    373488
     489TRUSTED_DIRECTORY:
    374490    /*
    375491     * Error out if the target username is invalid.
    376492     */
     
    452568     * Error out if attempt is made to execute as root or as
    453569     * a UID less than AP_UID_MIN.  Tsk tsk.
    454570     */
    455     if ((uid == 0) || (uid < AP_UID_MIN)) {
     571    if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) { /* uid 102 = signup  */
    456572        log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd);
    457573        exit(107);
    458574    }
     
    484599        log_err("failed to setuid (%ld: %s)\n", uid, cmd);
    485600        exit(110);
    486601    }
     602    setenv("HOME", target_homedir, 1);
    487603
    488604    /*
    489605     * Get the current working directory, as well as the proper
     
    506637            log_err("cannot get docroot information (%s)\n", target_homedir);
    507638            exit(112);
    508639        }
     640        size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1;
     641        char *expected = malloc(expected_len);
     642        snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX);
     643        if (strncmp(cwd, expected, expected_len-1) != 0) {
     644            log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected);
     645            exit(114);
     646        }
     647    }
     648    else if (trusteddir) {
     649        if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) ||
     650            ((getcwd(dwd, AP_MAXPATH)) == NULL) |
     651            ((chdir(cwd)) != 0)) {
     652            log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY);
     653            exit(112);
     654        }
    509655    }
    510656    else {
    511657        if (((chdir(AP_DOC_ROOT)) != 0) ||
     
    532678    /*
    533679     * Error out if cwd is writable by others.
    534680     */
     681#if 0
    535682    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
    536683        log_err("directory is writable by others: (%s)\n", cwd);
    537684        exit(116);
    538685    }
     686#endif
    539687
    540688    /*
    541689     * Error out if we cannot stat the program.
    542690     */
    543     if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
     691    if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) {
    544692        log_err("cannot stat program: (%s)\n", cmd);
    545693        exit(117);
    546694    }
     
    548696    /*
    549697     * Error out if the program is writable by others.
    550698     */
     699#if 0
    551700    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
    552701        log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
    553702        exit(118);
    554703    }
     704#endif
    555705
    556706    /*
    557707     * Error out if the file is setuid or setgid.
     
    565715     * Error out if the target name/group is different from
    566716     * the name/group of the cwd or the program.
    567717     */
     718#if 0
    568719    if ((uid != dir_info.st_uid) ||
    569720        (gid != dir_info.st_gid) ||
    570721        (uid != prg_info.st_uid) ||
     
    576727                prg_info.st_uid, prg_info.st_gid);
    577728        exit(120);
    578729    }
     730#endif
    579731    /*
    580732     * Error out if the program is not executable for the user.
    581733     * Otherwise, she won't find any error in the logs except for
    582734     * "[error] Premature end of script headers: ..."
    583735     */
    584     if (!(prg_info.st_mode & S_IXUSR)) {
     736    if (!is_static_extension(cmd) && !is_php_extension(cmd) &&
     737        !(prg_info.st_mode & S_IXUSR)) {
    585738        log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
    586739        exit(121);
    587740    }
     
    614767    /*
    615768     * Execute the command, replacing our image with its own.
    616769     */
     770    if (is_static_extension(cmd)) {
     771        if (setenv("PATH_TRANSLATED", cmd, 1) != 0) {
     772            log_err("setenv failed\n");
     773            exit(255);
     774        }
     775        execl(STATIC_CAT_PATH, STATIC_CAT_PATH, (const char *)NULL);
     776        log_err("(%d)%s: static-cat exec failed (%s)\n", errno, strerror(errno), STATIC_CAT_PATH);
     777        exit(255);
     778    }
     779    if (is_php_extension(cmd)) {
     780        setenv("PHPRC", ".", 1);
     781        argv[1] = PHP_PATH;
     782        argv[2] = "-f";
     783        /*
     784         * argv[3] is the command to run. argv[4] is either an argument or
     785         * already null. We don't want to pass any arguments through from
     786         * Apache (since they're untrusted), so we chop off the remainder
     787         * of argv here.
     788         */
     789        argv[4] = 0;
     790        execv(PHP_PATH, &argv[1]);
     791        log_err("(%d)%s: php exec failed (%s)\n", errno, strerror(errno), argv[1]);
     792        exit(255);
     793    }
    617794#ifdef NEED_HASHBANG_EMUL
    618795    /* We need the #! emulation when we want to execute scripts */
    619796    {
Note: See TracBrowser for help on using the repository browser.