Description: Fix race condition with chdir
 Fix /var/www* being accepted as docroot instead of /var/www/*
 (the same for public_html* instead of public_html/* )
Author: Stefan Fritsch <sf@debian.org>
Last-Update: 2014-05-29
Bug: https://issues.apache.org/bugzilla/show_bug.cgi?id=44752
--- a/support/suexec.c
+++ b/support/suexec.c
@@ -42,6 +42,7 @@
 #if APR_HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#include <fcntl.h>
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -281,11 +282,12 @@
     char *actual_gname;     /* actual group name         */
     char *cmd;              /* command to be executed    */
     char cwd[AP_MAXPATH];   /* current working directory */
-    char dwd[AP_MAXPATH];   /* docroot working directory */
+    char dwd[AP_MAXPATH+1]; /* docroot working directory */
     struct passwd *pw;      /* password entry holder     */
     struct group *gr;       /* group entry holder        */
     struct stat dir_info;   /* directory info holder     */
     struct stat prg_info;   /* program info holder       */
+    int cwdh;               /* handle to cwd             */
 
     /*
      * Start with a "clean" environment
@@ -529,11 +531,16 @@
         exit(111);
     }
 
+    if ( (cwdh = open(".", O_RDONLY)) == -1 ) {
+        log_err("cannot open current working directory\n");
+        exit(111);
+    }
+
     if (userdir) {
         if (((chdir(target_homedir)) != 0) ||
             ((chdir(AP_USERDIR_SUFFIX)) != 0) ||
             ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
-            ((chdir(cwd)) != 0)) {
+            ((fchdir(cwdh)) != 0)) {
             log_err("cannot get docroot information (%s)\n", target_homedir);
             exit(112);
         }
@@ -541,12 +548,16 @@
     else {
         if (((chdir(AP_DOC_ROOT)) != 0) ||
             ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
-            ((chdir(cwd)) != 0)) {
+            ((fchdir(cwdh)) != 0)) {
             log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT);
             exit(113);
         }
     }
 
+    close(cwdh);
+
+    if (strlen(cwd) > strlen(dwd))
+        strncat(dwd, "/", 1);
     if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
         log_err("command not in docroot (%s/%s)\n", cwd, cmd);
         exit(114);
