Selaa lähdekoodia

protect better against malicious directory naming

David Rose 16 vuotta sitten
vanhempi
sitoutus
2b004124f9

+ 9 - 2
direct/src/p3d/HostInfo.py

@@ -372,10 +372,17 @@ class HostInfo:
         if hostDirBasename:
         if hostDirBasename:
             # If the contents.xml specified a host_dir parameter, use
             # If the contents.xml specified a host_dir parameter, use
             # it.
             # it.
-            self.hostDir = Filename(self.appRunner.rootDir, hostDirBasename)
+            self.hostDir = self.appRunner.rootDir + '/hosts'
+            for component in hostDirBasename.split('/'):
+                if component:
+                    if component[0] == '.':
+                        # Forbid ".foo" or "..".
+                        component = 'x' + component
+                    self.hostDir += '/'
+                    self.hostDir += component
             return
             return
 
 
-        hostDir = ''
+        hostDir = 'hosts/'
 
 
         # Look for a server name in the URL.  Including this string in the
         # Look for a server name in the URL.  Including this string in the
         # directory name makes it friendlier for people browsing the
         # directory name makes it friendlier for people browsing the

+ 3 - 3
direct/src/plugin/p3dHost.cxx

@@ -448,16 +448,16 @@ void P3DHost::
 determine_host_dir(const string &host_dir_basename) {
 determine_host_dir(const string &host_dir_basename) {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   _host_dir = inst_mgr->get_root_dir();
   _host_dir = inst_mgr->get_root_dir();
-  _host_dir += "/";
+  _host_dir += "/hosts";
 
 
   if (!host_dir_basename.empty()) {
   if (!host_dir_basename.empty()) {
     // If the contents.xml specified a host_dir parameter, use it.
     // If the contents.xml specified a host_dir parameter, use it.
-    _host_dir += host_dir_basename;
+    inst_mgr->append_safe_dir(_host_dir, host_dir_basename);
     return;
     return;
   }
   }
 
 
   // If we didn't get a host_dir parameter, we have to make one up.
   // If we didn't get a host_dir parameter, we have to make one up.
-
+  _host_dir += "/";
   string hostname;
   string hostname;
 
 
   // Look for a server name in the URL.  Including this string in the
   // Look for a server name in the URL.  Including this string in the

+ 65 - 16
direct/src/plugin/p3dInstanceManager.cxx

@@ -959,6 +959,34 @@ cert_to_der(X509 *cert) {
   return result;
   return result;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_global_ptr
+//       Access: Public, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DInstanceManager *P3DInstanceManager::
+get_global_ptr() {
+  if (_global_ptr == NULL) {
+    _global_ptr = new P3DInstanceManager;
+  }
+  return _global_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::delete_global_ptr
+//       Access: Public, Static
+//  Description: This is called only at plugin shutdown time; it
+//               deletes the global instance manager pointer and
+//               clears it to NULL.
+////////////////////////////////////////////////////////////////////
+void P3DInstanceManager::
+delete_global_ptr() {
+  if (_global_ptr != NULL) {
+    delete _global_ptr;
+    _global_ptr = NULL;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::scan_directory
 //     Function: P3DInstanceManager::scan_directory
 //       Access: Public, Static
 //       Access: Public, Static
@@ -1120,31 +1148,52 @@ remove_file_from_list(vector<string> &contents, const string &filename) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DInstanceManager::get_global_ptr
+//     Function: P3DInstanceManager::append_safe_dir
 //       Access: Public, Static
 //       Access: Public, Static
-//  Description: 
+//  Description: Appends the indicated basename to the root directory
+//               name, which is modified in-place.  The basename is
+//               allowed to contain nested slashes, but no directory
+//               component of the basename may begin with a ".", thus
+//               precluding ".." and hidden files.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-P3DInstanceManager *P3DInstanceManager::
-get_global_ptr() {
-  if (_global_ptr == NULL) {
-    _global_ptr = new P3DInstanceManager;
+void P3DInstanceManager::
+append_safe_dir(string &root, const string &basename) {
+  if (basename.empty()) {
+    return;
+  }
+
+  size_t p = 0;
+  while (p < basename.length()) {
+    size_t q = basename.find('/', p);
+    if (q == string::npos) {
+      if (q != p) {
+        append_safe_dir_component(root, basename.substr(p));
+      }
+      return;
+    }
+    if (q != p) {
+      append_safe_dir_component(root, basename.substr(p, q - p));
+    }
+    p = q + 1;
   }
   }
-  return _global_ptr;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DInstanceManager::delete_global_ptr
-//       Access: Public, Static
-//  Description: This is called only at plugin shutdown time; it
-//               deletes the global instance manager pointer and
-//               clears it to NULL.
+//     Function: P3DInstanceManager::append_safe_dir_component
+//       Access: Private, Static
+//  Description: Appends a single directory component, implementing
+//               append_safe_dir(), above.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstanceManager::
 void P3DInstanceManager::
-delete_global_ptr() {
-  if (_global_ptr != NULL) {
-    delete _global_ptr;
-    _global_ptr = NULL;
+append_safe_dir_component(string &root, const string &component) {
+  if (component.empty()) {
+    return;
+  }
+  root += '/';
+  if (component[0] == '.') {
+    root += 'x';
   }
   }
+  root += component;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 6 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -133,6 +133,12 @@ public:
   static bool scan_directory_recursively(const string &dirname, vector<string> &contents,
   static bool scan_directory_recursively(const string &dirname, vector<string> &contents,
                                          const string &prefix = "");
                                          const string &prefix = "");
   static bool remove_file_from_list(vector<string> &contents, const string &filename);
   static bool remove_file_from_list(vector<string> &contents, const string &filename);
+
+  static void append_safe_dir(string &root, const string &basename);
+
+private:
+  static void append_safe_dir_component(string &root, const string &component);
+
 private:
 private:
   // The notify thread.  This thread runs only for the purpose of
   // The notify thread.  This thread runs only for the purpose of
   // generating asynchronous notifications of requests, to callers who
   // generating asynchronous notifications of requests, to callers who

+ 4 - 3
direct/src/plugin/p3dSession.cxx

@@ -721,8 +721,7 @@ start_p3dpython(P3DInstance *inst) {
       }
       }
     }
     }
     if (!start_dir.empty()) {
     if (!start_dir.empty()) {
-      _start_dir += "/";
-      _start_dir += start_dir;
+      inst_mgr->append_safe_dir(_start_dir, start_dir);
     }
     }
 
 
     mkdir_complete(_start_dir, nout);
     mkdir_complete(_start_dir, nout);
@@ -785,7 +784,9 @@ start_p3dpython(P3DInstance *inst) {
   if (!prc_name.empty()) {
   if (!prc_name.empty()) {
     // Add the prc_name to the path too, even if this directory doesn't
     // Add the prc_name to the path too, even if this directory doesn't
     // actually exist.
     // actually exist.
-    prc_path = inst_mgr->get_root_dir() + "/prc/" + prc_name + sep + prc_path;    
+    string this_prc_dir = inst_mgr->get_root_dir() + "/prc";
+    inst_mgr->append_safe_dir(this_prc_dir, prc_name);
+    prc_path = this_prc_dir + sep + prc_path;    
   }
   }
 
 
   if (keep_pythonpath) {
   if (keep_pythonpath) {