source: branches/fc19-dev/server/common/patches/httpd-suexec-scripts.patch @ 2435

Last change on this file since 2435 was 2422, checked in by tboning, 11 years ago
Rebase Scripts httpd patches for httpd 2.4:
File size: 9.7 KB
  • configure.in

    From 8445788d68230b2e18739166f4c3ae6434038421 Mon Sep 17 00:00:00 2001
    From: Alexander Chernyakhovsky <achernya@mit.edu>
    Date: Fri, 3 May 2013 21:38:58 -0400
    Subject: [PATCH 1/4] Add scripts-specific support to suexec
    
    This patch make suexec aware of static-cat, Scripts' tool to serve
    static content out of AFS.  Specifically, this introduces a whitelist
    of extensions for which suexec is supposed to invoke static-cat as a
    content-handler.
    
    Additionally, this patch also sets JAVA_TOOL_OPTIONS, to allow the JVM
    to start up in Scripts' limited memory environment.
    
    Furthermore, this patch deals with some of suexec's paranoia being
    incorrect in an AFS world, by ignoring some of the irrelevant stat
    results.
    
    Finally, add support for invoking php-cgi for php files, in a safe
    manner that will strip arguments passed by Apache to php-cgi.
    ---
     configure.in     |    4 ++
     support/suexec.c |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
     2 files changed, 173 insertions(+), 3 deletions(-)
    
    diff --git a/configure.in b/configure.in
    index d93f78c..14faccf 100644
    a b AC_ARG_WITH(suexec-userdir, 
    720720APACHE_HELP_STRING(--with-suexec-userdir,User subdirectory),[
    721721  AC_DEFINE_UNQUOTED(AP_USERDIR_SUFFIX, "$withval", [User subdirectory] ) ] )
    722722
     723AC_ARG_WITH(suexec-trusteddir,
     724APACHE_HELP_STRING(--with-suexec-trusteddir,Trusted SuExec directory),[
     725  AC_DEFINE_UNQUOTED(AP_TRUSTED_DIRECTORY, "$withval", [Trusted SuExec directory] ) ] )
     726
    723727AC_ARG_WITH(suexec-docroot,
    724728APACHE_HELP_STRING(--with-suexec-docroot,SuExec root directory),[
    725729  AC_DEFINE_UNQUOTED(AP_DOC_ROOT, "$withval", [SuExec root directory] ) ] )
  • support/suexec.c

    diff --git a/support/suexec.c b/support/suexec.c
    index 5b6b254..e377042 100644
    a b  
    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"
    static const char *const safe_env_lst[] = 
    9295{
    9396    /* variable name starts with */
    9497    "HTTP_",
     98    "HTTPS_",
    9599    "SSL_",
    96100
    97101    /* variable name is */
    static void clean_env(void) 
    264268    environ = cleanenv;
    265269}
    266270
     271static const char *static_extensions[] = {
     272    "html",
     273    "css",
     274    "gif",
     275    "jpg",
     276    "png",
     277    "htm",
     278    "jpeg",
     279    "js",
     280    "ico",
     281    "xml",
     282    "xsl",
     283    "tiff",
     284    "tif",
     285    "tgz",
     286    "tar",
     287    "jar",
     288    "zip",
     289    "pdf",
     290    "ps",
     291    "doc",
     292    "xls",
     293    "ppt",
     294    "dot",
     295    "docx",
     296    "dotx",
     297    "docm",
     298    "dotm",
     299    "xlt",
     300    "xla",
     301    "xlsx",
     302    "xltx",
     303    "xlsm",
     304    "xltm",
     305    "xlam",
     306    "xlsb",
     307    "pot",
     308    "pps",
     309    "ppa",
     310    "pptx",
     311    "potx",
     312    "ppsx",
     313    "ppam",
     314    "pptm",
     315    "potm",
     316    "ppsm",
     317    "swf",
     318    "mp3",
     319    "mov",
     320    "wmv",
     321    "mpg",
     322    "mpeg",
     323    "avi",
     324    "il",
     325    "xhtml",
     326    "svg",
     327    "xaml",
     328    "xap",
     329    "wav",
     330    "mid",
     331    "midi",
     332    "ttf",
     333    "otf",
     334    "odc",
     335    "odb",
     336    "odf",
     337    "odg",
     338    "otg",
     339    "odi",
     340    "odp",
     341    "otp",
     342    "ods",
     343    "ots",
     344    "odt",
     345    "odm",
     346    "ott",
     347    "oth",
     348    NULL
     349};
     350
     351static int is_static_extension(const char *file)
     352{
     353    const char *extension = strrchr(file, '.');
     354    const char **p;
     355    if (extension == NULL) return 0;
     356    for (p = static_extensions; *p; ++p) {
     357        if (strcasecmp(extension + 1, *p) == 0) return 1;
     358    }
     359    return 0;
     360}
     361
     362static int is_php_extension(const char *file)
     363{
     364    const char *extension = strrchr(file, '.');
     365    if (extension == NULL) return 0;
     366    return strcmp(extension + 1, "php") == 0;
     367}
     368
    267369int main(int argc, char *argv[])
    268370{
    269371    int userdir = 0;        /* ~userdir flag             */
     372    int trusteddir = 0;     /* TRUSTED_DIRECTORY flag    */
    270373    uid_t uid;              /* user information          */
    271374    gid_t gid;              /* target group placeholder  */
    272375    char *target_uname;     /* target user name          */
    int main(int argc, char *argv[]) 
    286389     * Start with a "clean" environment
    287390     */
    288391    clean_env();
     392    setenv("JAVA_TOOL_OPTIONS", "-Xmx128M", 1); /* scripts.mit.edu local hack */
    289393
    290394    /*
    291395     * Check existence/validity of the UID of the user
    int main(int argc, char *argv[]) 
    369473#endif /*_OSD_POSIX*/
    370474
    371475    /*
     476     * First check if this is an absolute path to the directory
     477     * of trusted executables. These are supposed to be security
     478     * audited to check parameters and validity on their own...
     479     */
     480    if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) {
     481        if (strstr(cmd, "/../") != NULL) {
     482            log_err("invalid command (%s)\n", cmd);
     483            exit(104);
     484        }
     485        trusteddir = 1;
     486        goto TRUSTED_DIRECTORY;
     487    }
     488
     489    /*
    372490     * Check for a leading '/' (absolute path) in the command to be executed,
    373491     * or attempts to back up out of the current directory,
    374492     * to protect against attacks.  If any are
    int main(int argc, char *argv[]) 
    390508        userdir = 1;
    391509    }
    392510
     511TRUSTED_DIRECTORY:
    393512    /*
    394513     * Error out if the target username is invalid.
    395514     */
    int main(int argc, char *argv[]) 
    471590     * Error out if attempt is made to execute as root or as
    472591     * a UID less than AP_UID_MIN.  Tsk tsk.
    473592     */
    474     if ((uid == 0) || (uid < AP_UID_MIN)) {
     593    if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) { /* uid 102 = signup  */
    475594        log_err("cannot run as forbidden uid (%lu/%s)\n", (unsigned long)uid, cmd);
    476595        exit(107);
    477596    }
    int main(int argc, char *argv[]) 
    503622        log_err("failed to setuid (%lu: %s)\n", (unsigned long)uid, cmd);
    504623        exit(110);
    505624    }
     625    setenv("HOME", target_homedir, 1);
    506626
    507627    /*
    508628     * Get the current working directory, as well as the proper
    int main(int argc, char *argv[]) 
    525645            log_err("cannot get docroot information (%s)\n", target_homedir);
    526646            exit(112);
    527647        }
     648        size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1;
     649        char *expected = malloc(expected_len);
     650        snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX);
     651        if (strncmp(cwd, expected, expected_len-1) != 0) {
     652            log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected);
     653            exit(114);
     654        }
     655    }
     656    else if (trusteddir) {
     657        if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) ||
     658            ((getcwd(dwd, AP_MAXPATH)) == NULL) |
     659            ((chdir(cwd)) != 0)) {
     660            log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY);
     661            exit(112);
     662        }
    528663    }
    529664    else {
    530665        if (((chdir(AP_DOC_ROOT)) != 0) ||
    int main(int argc, char *argv[]) 
    551686    /*
    552687     * Error out if cwd is writable by others.
    553688     */
     689#if 0
    554690    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
    555691        log_err("directory is writable by others: (%s)\n", cwd);
    556692        exit(116);
    557693    }
     694#endif
    558695
    559696    /*
    560697     * Error out if we cannot stat the program.
    561698     */
    562     if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
     699    if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) {
    563700        log_err("cannot stat program: (%s)\n", cmd);
    564701        exit(117);
    565702    }
    int main(int argc, char *argv[]) 
    567704    /*
    568705     * Error out if the program is writable by others.
    569706     */
     707#if 0
    570708    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
    571709        log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
    572710        exit(118);
    573711    }
     712#endif
    574713
    575714    /*
    576715     * Error out if the file is setuid or setgid.
    int main(int argc, char *argv[]) 
    584723     * Error out if the target name/group is different from
    585724     * the name/group of the cwd or the program.
    586725     */
     726#if 0
    587727    if ((uid != dir_info.st_uid) ||
    588728        (gid != dir_info.st_gid) ||
    589729        (uid != prg_info.st_uid) ||
    int main(int argc, char *argv[]) 
    595735                (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid);
    596736        exit(120);
    597737    }
     738#endif
    598739    /*
    599740     * Error out if the program is not executable for the user.
    600741     * Otherwise, she won't find any error in the logs except for
    601742     * "[error] Premature end of script headers: ..."
    602743     */
    603     if (!(prg_info.st_mode & S_IXUSR)) {
     744    if (!is_static_extension(cmd) && !is_php_extension(cmd) &&
     745        !(prg_info.st_mode & S_IXUSR)) {
    604746        log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
    605747        exit(121);
    606748    }
    int main(int argc, char *argv[]) 
    649791    /*
    650792     * Execute the command, replacing our image with its own.
    651793     */
     794    if (is_static_extension(cmd)) {
     795        if (setenv("PATH_TRANSLATED", cmd, 1) != 0) {
     796            log_err("setenv failed\n");
     797            exit(255);
     798        }
     799        execl(STATIC_CAT_PATH, STATIC_CAT_PATH, (const char *)NULL);
     800        log_err("(%d)%s: static-cat exec failed (%s)\n", errno, strerror(errno), STATIC_CAT_PATH);
     801        exit(255);
     802    }
     803    if (is_php_extension(cmd)) {
     804        setenv("PHPRC", ".", 1);
     805        argv[1] = PHP_PATH;
     806        argv[2] = "-f";
     807        /*
     808         * argv[3] is the command to run. argv[4] is either an argument or
     809         * already null. We don't want to pass any arguments through from
     810         * Apache (since they're untrusted), so we chop off the remainder
     811         * of argv here.
     812         */
     813        argv[4] = 0;
     814        execv(PHP_PATH, &argv[1]);
     815        log_err("(%d)%s: php exec failed (%s)\n", errno, strerror(errno), argv[1]);
     816        exit(255);
     817    }
    652818#ifdef NEED_HASHBANG_EMUL
    653819    /* We need the #! emulation when we want to execute scripts */
    654820    {
Note: See TracBrowser for help on using the repository browser.