From owner-svn-ports-head@FreeBSD.ORG Wed Mar 18 19:43:44 2015 Return-Path: Delivered-To: svn-ports-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C6ED9961; Wed, 18 Mar 2015 19:43:44 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A85C0F4F; Wed, 18 Mar 2015 19:43:44 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t2IJhiYE051799; Wed, 18 Mar 2015 19:43:44 GMT (envelope-from martymac@FreeBSD.org) Received: (from martymac@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t2IJhh7G051792; Wed, 18 Mar 2015 19:43:43 GMT (envelope-from martymac@FreeBSD.org) Message-Id: <201503181943.t2IJhh7G051792@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: martymac set sender to martymac@FreeBSD.org using -f From: Ganael LAPLANCHE Date: Wed, 18 Mar 2015 19:43:43 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r381575 - in head/games: flightgear flightgear-data flightgear-data/files flightgear/files X-SVN-Group: ports-head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the ports tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 18 Mar 2015 19:43:45 -0000 Author: martymac Date: Wed Mar 18 19:43:42 2015 New Revision: 381575 URL: https://svnweb.freebsd.org/changeset/ports/381575 QAT: https://qat.redports.org/buildarchive/r381575/ Log: While waiting for a bugfix release, backport Nasal security fixes from upstream git repositories: - flightgear 6a30e70 - fgdata 60da209 Suggested by: "Rebecca N. Palmer" Added: head/games/flightgear-data/files/ head/games/flightgear-data/files/patch-60da209 (contents, props changed) head/games/flightgear/files/patch-6a30e70 (contents, props changed) Modified: head/games/flightgear-data/Makefile head/games/flightgear/Makefile Modified: head/games/flightgear-data/Makefile ============================================================================== --- head/games/flightgear-data/Makefile Wed Mar 18 19:43:06 2015 (r381574) +++ head/games/flightgear-data/Makefile Wed Mar 18 19:43:42 2015 (r381575) @@ -3,6 +3,7 @@ PORTNAME= flightgear-data PORTVERSION= 3.4.0 +PORTREVISION= 1 CATEGORIES= games # see http://www.flightgear.org/templates.js MASTER_SITES= http://mirrors.ibiblio.org/flightgear/ftp/Shared/ \ Added: head/games/flightgear-data/files/patch-60da209 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/games/flightgear-data/files/patch-60da209 Wed Mar 18 19:43:42 2015 (r381575) @@ -0,0 +1,10 @@ +--- Nasal/IOrules.orig ++++ Nasal/IOrules +@@ -28,7 +28,6 @@ + READ ALLOW $FG_ROOT/* + READ ALLOW $FG_HOME/* + READ ALLOW $FG_AIRCRAFT/* +-READ ALLOW $FG_SCENERY/* + + WRITE ALLOW /tmp/*.xml + WRITE ALLOW $FG_HOME/*.sav Modified: head/games/flightgear/Makefile ============================================================================== --- head/games/flightgear/Makefile Wed Mar 18 19:43:06 2015 (r381574) +++ head/games/flightgear/Makefile Wed Mar 18 19:43:42 2015 (r381575) @@ -3,6 +3,7 @@ PORTNAME= flightgear PORTVERSION= 3.4.0 +PORTREVISION= 1 CATEGORIES= games # see http://www.flightgear.org/templates.js MASTER_SITES= http://mirrors.ibiblio.org/flightgear/ftp/Source/ \ Added: head/games/flightgear/files/patch-6a30e70 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/games/flightgear/files/patch-6a30e70 Wed Mar 18 19:43:42 2015 (r381575) @@ -0,0 +1,208 @@ +--- src/Main/util.cxx.orig ++++ src/Main/util.cxx +@@ -33,6 +33,7 @@ + #include + #include + ++#include + #include "fg_io.hxx" + #include "fg_props.hxx" + #include "globals.hxx" +@@ -71,32 +72,142 @@ fgGetLowPass (double current, double target, double timeratio) + return current; + } + +-// Write out path to validation node and read it back in. A Nasal +-// listener is supposed to replace the path with a validated version +-// or an empty string otherwise. +-const char *fgValidatePath (const char *str, bool write) ++static string_list read_allowed_paths; ++static string_list write_allowed_paths; ++ ++// Allowed paths here are absolute, and may contain _one_ *, ++// which matches any string ++// FG_SCENERY is deliberately not allowed, as it would make ++// /sim/terrasync/scenery-dir a security hole ++void fgInitAllowedPaths() + { +- SGPropertyNode_ptr r, w; +- r = fgGetNode("/sim/paths/validate/read", true); +- r->setAttribute(SGPropertyNode::READ, true); +- r->setAttribute(SGPropertyNode::WRITE, true); +- +- w = fgGetNode("/sim/paths/validate/write", true); +- w->setAttribute(SGPropertyNode::READ, true); +- w->setAttribute(SGPropertyNode::WRITE, true); +- +- SGPropertyNode *prop = write ? w : r; +- prop->setStringValue(str); +- const char *result = prop->getStringValue(); +- return result[0] ? result : 0; ++ read_allowed_paths.clear(); ++ write_allowed_paths.clear(); ++ read_allowed_paths.push_back(globals->get_fg_root() + "/*"); ++ read_allowed_paths.push_back(globals->get_fg_home() + "/*"); ++ string_list const aircraft_paths = globals->get_aircraft_paths(); ++ for( string_list::const_iterator it = aircraft_paths.begin(); ++ it != aircraft_paths.end(); ++ ++it ) ++ { ++ read_allowed_paths.push_back(*it + "/*"); ++ } ++ ++ for( string_list::const_iterator it = read_allowed_paths.begin(); ++ it != read_allowed_paths.end(); ++ ++it ) ++ { // if we get the initialization order wrong, better to have an ++ // obvious error than a can-read-everything security hole... ++ if (!(it->compare("/*"))){ ++ flightgear::fatalMessageBox("Nasal initialization error", ++ "Empty string in FG_ROOT, FG_HOME or FG_AIRCRAFT", ++ "or fgInitAllowedPaths() called too early"); ++ exit(-1); ++ } ++ } ++ write_allowed_paths.push_back("/tmp/*.xml"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/*.sav"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/*.log"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/cache/*"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/Export/*"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/state/*.xml"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/aircraft-data/*.xml"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/Wildfire/*.xml"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/runtime-jetways/*.xml"); ++ write_allowed_paths.push_back(globals->get_fg_home() + "/Input/Joysticks/*.xml"); ++ ++ if(!fgValidatePath(globals->get_fg_home() + "/../no.log",true).empty() || ++ !fgValidatePath(globals->get_fg_home() + "/no.lot",true).empty() || ++ fgValidatePath((globals->get_fg_home() + "/nolog").c_str(),true) || ++ !fgValidatePath(globals->get_fg_home() + "no.log",true).empty() || ++ !fgValidatePath("..\\" + globals->get_fg_home() + "/no.log",false).empty() || ++ fgValidatePath("/tmp/no.xml",false) || ++ fgValidatePath(globals->get_fg_home() + "/./ff/../Export\\yes..gg",true).empty() || ++ !fgValidatePath((globals->get_fg_home() + "/aircraft-data/yes..xml").c_str(),true) || ++ fgValidatePath(globals->get_fg_root() + "/./\\yes.bmp",false).empty()) { ++ flightgear::fatalMessageBox("Nasal initialization error", ++ "fgInitAllowedPaths() does not work", ++ ""); ++ exit(-1); ++ } + } + +-//------------------------------------------------------------------------------ +-std::string fgValidatePath(const std::string& path, bool write) ++// Normalize a path ++// Unlike SGPath::realpath, does not require that the file already exists, ++// but does require that it be below the starting point ++static std::string fgNormalizePath (const std::string& path) + { +- const char* validate_path = fgValidatePath(path.c_str(), write); +- return std::string(validate_path ? validate_path : ""); +-} ++ string_list path_parts; ++ char c; ++ std::string normed_path = "", this_part = ""; ++ ++ for (int pos = 0; ; pos++) { ++ c = path[pos]; ++ if (c == '\\') { c = '/'; } ++ if ((c == '/') || (c == 0)) { ++ if ((this_part == "/..") || (this_part == "..")) { ++ if (path_parts.empty()) { return ""; } ++ path_parts.pop_back(); ++ } else if ((this_part != "/.") && (this_part != "/")) { ++ path_parts.push_back(this_part); ++ } ++ this_part = ""; ++ } ++ if (c == 0) { break; } ++ this_part = this_part + c; ++ } ++ for( string_list::const_iterator it = path_parts.begin(); ++ it != path_parts.end(); ++ ++it ) ++ { ++ normed_path.append(*it); ++ } ++ return normed_path; ++ } ++ + ++// Check whether Nasal is allowed to access a path ++std::string fgValidatePath (const std::string& path, bool write) ++{ ++ const string_list& allowed_paths(write ? write_allowed_paths : read_allowed_paths); ++ int star_pos; ++ ++ // Normalize the path (prevents ../../.. trickery) ++ std::string normed_path = fgNormalizePath(path); ++ ++ // Check against each allowed pattern ++ for( string_list::const_iterator it = allowed_paths.begin(); ++ it != allowed_paths.end(); ++ ++it ) ++ { ++ star_pos = it->find('*'); ++ if (star_pos == std::string::npos) { ++ if (!(it->compare(normed_path))) { ++ return normed_path; ++ } ++ } else { ++ if ((it->size()-1 <= normed_path.size()) /* long enough to be a potential match */ ++ && !(it->substr(0,star_pos) ++ .compare(normed_path.substr(0,star_pos))) /* before-star parts match */ ++ && !(it->substr(star_pos+1,it->size()-star_pos-1) ++ .compare(normed_path.substr(star_pos+1+normed_path.size()-it->size(), ++ it->size()-star_pos-1))) /* after-star parts match */) { ++ return normed_path; ++ } ++ } ++ } ++ // no match found ++ return ""; ++} ++// s.c_str() becomes invalid when s is destroyed, so need a static s ++std::string validate_path_temp; ++const char* fgValidatePath(const char* path, bool write) ++{ ++ validate_path_temp = fgValidatePath(std::string(path), write); ++ if(validate_path_temp.empty()){ ++ return 0; ++ } ++ return validate_path_temp.c_str(); ++} + // end of util.cxx + +--- src/Main/util.hxx.orig ++++ src/Main/util.hxx +@@ -36,7 +36,7 @@ + double fgGetLowPass (double current, double target, double timeratio); + + /** +- * Validation listener interface for io.nas, used by fgcommands. ++ * File access control, used by Nasal and fgcommands. + * @param path Path to be validated + * @param write True for write operations and false for read operations. + * @return The validated path on success or 0 if access denied. +@@ -44,4 +44,9 @@ double fgGetLowPass (double current, double target, double timeratio); + const char *fgValidatePath (const char *path, bool write); + std::string fgValidatePath(const std::string& path, bool write); + ++/** ++ * Set allowed paths for fgValidatePath ++ */ ++void fgInitAllowedPaths(); ++ + #endif // __UTIL_HXX +--- src/Scripting/NasalSys.cxx.orig ++++ src/Scripting/NasalSys.cxx +@@ -835,6 +835,9 @@ void FGNasalSys::init() + .member("singleShot", &TimerObj::isSingleShot, &TimerObj::setSingleShot) + .member("isRunning", &TimerObj::isRunning); + ++ // Set allowed paths for Nasal I/O ++ fgInitAllowedPaths(); ++ + // Now load the various source files in the Nasal directory + simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); + loadScriptDirectory(nasalDir);