Replace fgValidatePath() with SGPath::validate()
Move the fgValidatePath() code and the two associated static variables 'read_allowed_paths' and 'write_allowed_paths' to SimGear. fgValidatePath() is now known as SGPath::validate(). This requires SimGear commit e002a481f481709263a.
This commit is contained in:
parent
199adf90df
commit
ee12883eb6
17 changed files with 66 additions and 136 deletions
|
@ -35,7 +35,6 @@
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <Scripting/NasalSys.hxx>
|
#include <Scripting/NasalSys.hxx>
|
||||||
|
|
||||||
#include "addon_fwd.hxx"
|
#include "addon_fwd.hxx"
|
||||||
|
@ -200,12 +199,12 @@ SGPath Addon::createStorageDir() const
|
||||||
throw errors::unable_to_create_addon_storage_dir(msg);
|
throw errors::unable_to_create_addon_storage_dir(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SGPath authorizedPath = fgValidatePath(_storagePath, true /* write */);
|
const SGPath authorizedPath = SGPath(_storagePath).validate(/* write */
|
||||||
|
true);
|
||||||
if (authorizedPath.isNull()) {
|
if (authorizedPath.isNull()) {
|
||||||
string msg =
|
string msg =
|
||||||
"Unable to create add-on storage directory because of the FlightGear "
|
"Unable to create add-on storage directory because of the FlightGear "
|
||||||
"security policy (refused by fgValidatePath()): '" +
|
"security policy (refused by SGPath::validate()): '" +
|
||||||
_storagePath.utf8Str() + "'";
|
_storagePath.utf8Str() + "'";
|
||||||
SG_LOG(SG_GENERAL, SG_POPUP, msg);
|
SG_LOG(SG_GENERAL, SG_POPUP, msg);
|
||||||
throw errors::unable_to_create_addon_storage_dir(msg);
|
throw errors::unable_to_create_addon_storage_dir(msg);
|
||||||
|
@ -218,8 +217,8 @@ SGPath Addon::createStorageDir() const
|
||||||
// _storagePath instead of authorizedPath for consistency with the
|
// _storagePath instead of authorizedPath for consistency with the
|
||||||
// getStoragePath() method (_storagePath and authorizedPath could be
|
// getStoragePath() method (_storagePath and authorizedPath could be
|
||||||
// different in case the former contains symlink components). Further
|
// different in case the former contains symlink components). Further
|
||||||
// sensitive operations beneath _storagePath must use fgValidatePath() again
|
// sensitive operations beneath _storagePath must use SGPath::validate()
|
||||||
// every time, of course (otherwise attackers could use symlinks in
|
// again every time, of course (otherwise, attackers could use symlinks in
|
||||||
// _storagePath to bypass the security policy).
|
// _storagePath to bypass the security policy).
|
||||||
return _storagePath;
|
return _storagePath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,8 +178,8 @@ string
|
||||||
AddonManager::registerAddon(const SGPath& addonPath)
|
AddonManager::registerAddon(const SGPath& addonPath)
|
||||||
{
|
{
|
||||||
// Use realpath() as in FGGlobals::append_aircraft_path(), otherwise
|
// Use realpath() as in FGGlobals::append_aircraft_path(), otherwise
|
||||||
// fgValidatePath() will deny access to resources under the add-on path if
|
// SGPath::validate() will deny access to resources under the add-on path
|
||||||
// one of its components is a symlink.
|
// if one of its components is a symlink.
|
||||||
const SGPath addonRealPath = addonPath.realpath();
|
const SGPath addonRealPath = addonPath.realpath();
|
||||||
const string addonId = registerAddonMetadata(addonRealPath);
|
const string addonId = registerAddonMetadata(addonRealPath);
|
||||||
loadConfigFileIfExists(addonRealPath / "addon-config.xml");
|
loadConfigFileIfExists(addonRealPath / "addon-config.xml");
|
||||||
|
|
|
@ -23,8 +23,6 @@
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
|
|
||||||
#include <Main/util.hxx>
|
|
||||||
|
|
||||||
#include "AddonManager.hxx"
|
#include "AddonManager.hxx"
|
||||||
#include "AddonResourceProvider.hxx"
|
#include "AddonResourceProvider.hxx"
|
||||||
|
|
||||||
|
@ -72,7 +70,7 @@ ResourceProvider::resolve(const string& resource, SGPath& context) const
|
||||||
return SGPath();
|
return SGPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
return fgValidatePath(candidate, /* write */ false);
|
return SGPath(candidate).validate(/* write */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace addons
|
} // of namespace addons
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#include "Airports/runways.hxx"
|
#include "Airports/runways.hxx"
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/new_gui.hxx>
|
||||||
#include <GUI/dialog.hxx>
|
#include <GUI/dialog.hxx>
|
||||||
#include <Main/util.hxx> // fgValidatePath()
|
|
||||||
#include <GUI/MessageBox.hxx>
|
#include <GUI/MessageBox.hxx>
|
||||||
|
|
||||||
#define RM "/autopilot/route-manager/"
|
#define RM "/autopilot/route-manager/"
|
||||||
|
@ -69,7 +68,7 @@ static bool commandSaveFlightPlan(const SGPropertyNode* arg, SGPropertyNode *)
|
||||||
{
|
{
|
||||||
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
|
||||||
SGPath path = SGPath::fromUtf8(arg->getStringValue("path"));
|
SGPath path = SGPath::fromUtf8(arg->getStringValue("path"));
|
||||||
SGPath authorizedPath = fgValidatePath(path, true /* write */);
|
const SGPath authorizedPath = SGPath(path).validate(true /* write */);
|
||||||
|
|
||||||
if (!authorizedPath.isNull()) {
|
if (!authorizedPath.isNull()) {
|
||||||
return self->saveRoute(authorizedPath);
|
return self->saveRoute(authorizedPath);
|
||||||
|
@ -768,7 +767,7 @@ void FGRouteMgr::InputListener::valueChanged(SGPropertyNode *prop)
|
||||||
mgr->loadRoute(path);
|
mgr->loadRoute(path);
|
||||||
} else if (input == "@SAVE") {
|
} else if (input == "@SAVE") {
|
||||||
SGPath path = SGPath::fromUtf8(mgr->_pathNode->getStringValue());
|
SGPath path = SGPath::fromUtf8(mgr->_pathNode->getStringValue());
|
||||||
SGPath authorizedPath = fgValidatePath(path, true /* write */);
|
const SGPath authorizedPath = SGPath(path).validate(true /* write */);
|
||||||
|
|
||||||
if (!authorizedPath.isNull()) {
|
if (!authorizedPath.isNull()) {
|
||||||
mgr->saveRoute(authorizedPath);
|
mgr->saveRoute(authorizedPath);
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "FGCanvasSystemAdapter.hxx"
|
#include "FGCanvasSystemAdapter.hxx"
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <Network/HTTPClient.hxx>
|
#include <Network/HTTPClient.hxx>
|
||||||
#include <Viewer/renderer.hxx>
|
#include <Viewer/renderer.hxx>
|
||||||
|
|
||||||
|
@ -88,7 +87,7 @@ namespace canvas
|
||||||
|
|
||||||
if( p.isAbsolute() )
|
if( p.isAbsolute() )
|
||||||
{
|
{
|
||||||
SGPath valid_path = fgValidatePath(p, false);
|
const SGPath valid_path = SGPath(p).validate(false);
|
||||||
if( !valid_path.isNull() )
|
if( !valid_path.isNull() )
|
||||||
return osgDB::readRefImageFile(valid_path.utf8Str(), localReaderWriterOptions);
|
return osgDB::readRefImageFile(valid_path.utf8Str(), localReaderWriterOptions);
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
#include "fg_props.hxx"
|
#include "fg_props.hxx"
|
||||||
#include "globals.hxx"
|
#include "globals.hxx"
|
||||||
#include "logger.hxx"
|
#include "logger.hxx"
|
||||||
#include "util.hxx"
|
|
||||||
#include "main.hxx"
|
#include "main.hxx"
|
||||||
#include "positioninit.hxx"
|
#include "positioninit.hxx"
|
||||||
|
|
||||||
|
@ -258,7 +257,7 @@ do_load (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||||
if (file.extension() != "sav")
|
if (file.extension() != "sav")
|
||||||
file.concat(".sav");
|
file.concat(".sav");
|
||||||
|
|
||||||
SGPath validated_path = fgValidatePath(file, false);
|
const SGPath validated_path = SGPath(file).validate(false);
|
||||||
if (validated_path.isNull()) {
|
if (validated_path.isNull()) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "load: reading '" << file << "' denied "
|
SG_LOG(SG_IO, SG_ALERT, "load: reading '" << file << "' denied "
|
||||||
"(unauthorized access)");
|
"(unauthorized access)");
|
||||||
|
@ -291,7 +290,7 @@ do_save (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||||
if (file.extension() != "sav")
|
if (file.extension() != "sav")
|
||||||
file.concat(".sav");
|
file.concat(".sav");
|
||||||
|
|
||||||
SGPath validated_path = fgValidatePath(file, true);
|
const SGPath validated_path = SGPath(file).validate(true);
|
||||||
if (validated_path.isNull()) {
|
if (validated_path.isNull()) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "save: writing '" << file << "' denied "
|
SG_LOG(SG_IO, SG_ALERT, "save: writing '" << file << "' denied "
|
||||||
"(unauthorized access)");
|
"(unauthorized access)");
|
||||||
|
@ -884,7 +883,7 @@ do_load_xml_to_proptree(const SGPropertyNode * arg, SGPropertyNode * root)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPath validated_path = fgValidatePath(file, false);
|
const SGPath validated_path = SGPath(file).validate(false);
|
||||||
if (validated_path.isNull()) {
|
if (validated_path.isNull()) {
|
||||||
SG_LOG(SG_IO, quiet ? SG_DEV_WARN : SG_ALERT, "loadxml: reading '" << file << "' denied "
|
SG_LOG(SG_IO, quiet ? SG_DEV_WARN : SG_ALERT, "loadxml: reading '" << file << "' denied "
|
||||||
"(unauthorized directory - authorization no longer follows symlinks; to authorize reading additional directories, pass them to --allow-nasal-read)");
|
"(unauthorized directory - authorization no longer follows symlinks; to authorize reading additional directories, pass them to --allow-nasal-read)");
|
||||||
|
@ -971,7 +970,7 @@ do_save_xml_from_proptree(const SGPropertyNode * arg, SGPropertyNode * root)
|
||||||
if (file.extension() != "xml")
|
if (file.extension() != "xml")
|
||||||
file.concat(".xml");
|
file.concat(".xml");
|
||||||
|
|
||||||
SGPath validated_path = fgValidatePath(file, true);
|
const SGPath validated_path = SGPath(file).validate(true);
|
||||||
if (validated_path.isNull()) {
|
if (validated_path.isNull()) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "savexml: writing to '" << file << "' denied "
|
SG_LOG(SG_IO, SG_ALERT, "savexml: writing to '" << file << "' denied "
|
||||||
"(unauthorized directory - authorization no longer follows symlinks)");
|
"(unauthorized directory - authorization no longer follows symlinks)");
|
||||||
|
|
|
@ -696,7 +696,7 @@ int fgInitConfig ( int argc, char **argv, bool reinit )
|
||||||
createBaseStorageDirForAddons(exportDir.path());
|
createBaseStorageDirForAddons(exportDir.path());
|
||||||
|
|
||||||
// Set /sim/fg-home. Use FG_HOME if necessary.
|
// Set /sim/fg-home. Use FG_HOME if necessary.
|
||||||
// deliberately not a tied property, for fgValidatePath security
|
// deliberately not a tied property, for SGPath::validate() security
|
||||||
// write-protect to avoid accidents
|
// write-protect to avoid accidents
|
||||||
SGPropertyNode *home = fgGetNode("/sim", true);
|
SGPropertyNode *home = fgGetNode("/sim", true);
|
||||||
home->removeChild("fg-home", 0);
|
home->removeChild("fg-home", 0);
|
||||||
|
@ -766,7 +766,7 @@ int fgInitConfig ( int argc, char **argv, bool reinit )
|
||||||
|
|
||||||
static void initAircraftDirsNasalSecurity()
|
static void initAircraftDirsNasalSecurity()
|
||||||
{
|
{
|
||||||
// deliberately not a tied property, for fgValidatePath security
|
// deliberately not a tied property, for SGPath::validate() security
|
||||||
// write-protect to avoid accidents
|
// write-protect to avoid accidents
|
||||||
SGPropertyNode* sim = fgGetNode("/sim", true);
|
SGPropertyNode* sim = fgGetNode("/sim", true);
|
||||||
sim->removeChildren("fg-aircraft");
|
sim->removeChildren("fg-aircraft");
|
||||||
|
|
|
@ -279,7 +279,7 @@ void FGGlobals::set_fg_root (const SGPath &root) {
|
||||||
<< fg_root << "'\n***\n***");
|
<< fg_root << "'\n***\n***");
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliberately not a tied property, for fgValidatePath security
|
// deliberately not a tied property, for SGPath::validate() security
|
||||||
// write-protect to avoid accidents
|
// write-protect to avoid accidents
|
||||||
SGPropertyNode *n = fgGetNode("/sim", true);
|
SGPropertyNode *n = fgGetNode("/sim", true);
|
||||||
n->removeChild("fg-root", 0);
|
n->removeChild("fg-root", 0);
|
||||||
|
@ -467,7 +467,7 @@ void FGGlobals::set_terrasync_dir(const SGPath &path)
|
||||||
}
|
}
|
||||||
SGPath abspath(path.realpath());
|
SGPath abspath(path.realpath());
|
||||||
terrasync_dir = abspath;
|
terrasync_dir = abspath;
|
||||||
// deliberately not a tied property, for fgValidatePath security
|
// deliberately not a tied property, for SGPath::validate() security
|
||||||
// write-protect to avoid accidents
|
// write-protect to avoid accidents
|
||||||
SGPropertyNode *n = fgGetNode("/sim/terrasync/scenery-dir", true);
|
SGPropertyNode *n = fgGetNode("/sim/terrasync/scenery-dir", true);
|
||||||
n->setAttribute(SGPropertyNode::WRITE, true);
|
n->setAttribute(SGPropertyNode::WRITE, true);
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include "fg_props.hxx"
|
#include "fg_props.hxx"
|
||||||
#include "globals.hxx"
|
#include "globals.hxx"
|
||||||
#include "util.hxx"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
@ -53,7 +52,7 @@ FGLogger::init ()
|
||||||
|
|
||||||
// Security: the path comes from the global Property Tree; it *must* be
|
// Security: the path comes from the global Property Tree; it *must* be
|
||||||
// validated before we overwrite the file.
|
// validated before we overwrite the file.
|
||||||
const SGPath authorizedPath = fgValidatePath(SGPath::fromUtf8(filename),
|
const SGPath authorizedPath = SGPath::fromUtf8(filename).validate(
|
||||||
/* write */ true);
|
/* write */ true);
|
||||||
|
|
||||||
if (authorizedPath.isNull()) {
|
if (authorizedPath.isNull()) {
|
||||||
|
@ -79,7 +78,7 @@ FGLogger::init ()
|
||||||
log.interval_ms = child->getLongValue("interval-ms");
|
log.interval_ms = child->getLongValue("interval-ms");
|
||||||
log.last_time_ms = globals->get_sim_time_sec() * 1000;
|
log.last_time_ms = globals->get_sim_time_sec() * 1000;
|
||||||
log.delimiter = delimiter.c_str()[0];
|
log.delimiter = delimiter.c_str()[0];
|
||||||
// Security: use the return value of fgValidatePath()
|
// Security: use the return value of SGPath::validate()
|
||||||
log.output.reset(new sg_ofstream(authorizedPath, std::ios_base::out));
|
log.output.reset(new sg_ofstream(authorizedPath, std::ios_base::out));
|
||||||
if ( !(*log.output) ) {
|
if ( !(*log.output) ) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot write log to " << filename);
|
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot write log to " << filename);
|
||||||
|
|
|
@ -667,8 +667,6 @@ int fgMainInit( int argc, char **argv )
|
||||||
string_list *col = new string_list;
|
string_list *col = new string_list;
|
||||||
globals->set_channel_options_list( col );
|
globals->set_channel_options_list( col );
|
||||||
|
|
||||||
fgValidatePath(globals->get_fg_home(), false); // initialize static variables
|
|
||||||
|
|
||||||
if (showLauncher) {
|
if (showLauncher) {
|
||||||
// to minimise strange interactions when launcher and config files
|
// to minimise strange interactions when launcher and config files
|
||||||
// set overlaping options, we disable the default files. Users can
|
// set overlaping options, we disable the default files. Users can
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
#include "fg_os.hxx"
|
#include "fg_os.hxx"
|
||||||
#include "fg_props.hxx"
|
#include "fg_props.hxx"
|
||||||
#include "options.hxx"
|
#include "options.hxx"
|
||||||
#include "util.hxx"
|
|
||||||
#include "main.hxx"
|
#include "main.hxx"
|
||||||
#include "locale.hxx"
|
#include "locale.hxx"
|
||||||
#include <Viewer/view.hxx>
|
#include <Viewer/view.hxx>
|
||||||
|
@ -2458,7 +2457,7 @@ OptionResult Options::initAircraft()
|
||||||
globals->append_read_allowed_paths(realAircraftPath);
|
globals->append_read_allowed_paths(realAircraftPath);
|
||||||
|
|
||||||
// Set this now, so it's available in FindAndCacheAircraft. Use realpath()
|
// Set this now, so it's available in FindAndCacheAircraft. Use realpath()
|
||||||
// as in FGGlobals::append_aircraft_path(), otherwise fgValidatePath()
|
// as in FGGlobals::append_aircraft_path(), otherwise SGPath::validate()
|
||||||
// will deny access to resources under this path if one of its components
|
// will deny access to resources under this path if one of its components
|
||||||
// is a symlink (which is not a problem, since it was given as is by the
|
// is a symlink (which is not a problem, since it was given as is by the
|
||||||
// user---this is very different from a symlink *under* the aircraft dir
|
// user---this is very different from a symlink *under* the aircraft dir
|
||||||
|
|
|
@ -72,9 +72,6 @@ fgGetLowPass (double current, double target, double timeratio)
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string_list read_allowed_paths;
|
|
||||||
static string_list write_allowed_paths;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allowed paths here are absolute, and may contain _one_ *,
|
* Allowed paths here are absolute, and may contain _one_ *,
|
||||||
* which matches any string
|
* which matches any string
|
||||||
|
@ -82,54 +79,54 @@ static string_list write_allowed_paths;
|
||||||
void fgInitAllowedPaths()
|
void fgInitAllowedPaths()
|
||||||
{
|
{
|
||||||
if(SGPath("ygjmyfvhhnvdoesnotexist").realpath().utf8Str() == "ygjmyfvhhnvdoesnotexist"){
|
if(SGPath("ygjmyfvhhnvdoesnotexist").realpath().utf8Str() == "ygjmyfvhhnvdoesnotexist"){
|
||||||
// Forbid using this version of fgValidatePath() with older
|
// Abort in case this is used with older versions of realpath()
|
||||||
// (not normalizing non-existent files) versions of realpath(),
|
// that don't normalize non-existent files, as that would be a security
|
||||||
// as that would be a security hole
|
// hole.
|
||||||
flightgear::fatalMessageBoxThenExit(
|
flightgear::fatalMessageBoxThenExit(
|
||||||
"Nasal initialization error",
|
"Nasal initialization error",
|
||||||
"Version mismatch - please update simgear");
|
"Version mismatch - please update simgear");
|
||||||
}
|
}
|
||||||
read_allowed_paths.clear();
|
SGPath::clearListOfAllowedPaths(false); // clear list of read-allowed paths
|
||||||
write_allowed_paths.clear();
|
SGPath::clearListOfAllowedPaths(true); // clear list of write-allowed paths
|
||||||
|
|
||||||
PathList read_paths = globals->get_extra_read_allowed_paths();
|
PathList read_paths = globals->get_extra_read_allowed_paths();
|
||||||
read_paths.push_back(globals->get_fg_root());
|
read_paths.push_back(globals->get_fg_root());
|
||||||
read_paths.push_back(globals->get_fg_home());
|
read_paths.push_back(globals->get_fg_home());
|
||||||
|
|
||||||
for( PathList::const_iterator it = read_paths.begin(); it != read_paths.end(); ++it )
|
for (const auto& path: read_paths) {
|
||||||
{
|
// If we get the initialization order wrong, better to have an
|
||||||
// if we get the initialization order wrong, better to have an
|
|
||||||
// obvious error than a can-read-everything security hole...
|
// obvious error than a can-read-everything security hole...
|
||||||
if (it->isNull()) {
|
if (path.isNull()) {
|
||||||
flightgear::fatalMessageBoxThenExit(
|
flightgear::fatalMessageBoxThenExit(
|
||||||
"Nasal initialization error",
|
"Nasal initialization error",
|
||||||
"Empty string in FG_ROOT, FG_HOME, FG_AIRCRAFT, FG_SCENERY or "
|
"Empty string in FG_ROOT, FG_HOME, FG_AIRCRAFT, FG_SCENERY or "
|
||||||
"--allow-nasal-read, or fgInitAllowedPaths() called too early");
|
"--allow-nasal-read, or fgInitAllowedPaths() called too early");
|
||||||
}
|
}
|
||||||
read_allowed_paths.push_back(it->realpath().utf8Str() + "/*");
|
SGPath::addAllowedPathPattern(path.realpath().utf8Str() + "/*",
|
||||||
read_allowed_paths.push_back(it->realpath().utf8Str());
|
false /* write */);
|
||||||
|
SGPath::addAllowedPathPattern(path.realpath().utf8Str(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fg_home = globals->get_fg_home().realpath().utf8Str();
|
const std::string fg_home = globals->get_fg_home().realpath().utf8Str();
|
||||||
write_allowed_paths.push_back(fg_home + "/*.sav");
|
SGPath::addAllowedPathPattern(fg_home + "/*.sav", true /* write */);
|
||||||
write_allowed_paths.push_back(fg_home + "/*.log");
|
SGPath::addAllowedPathPattern(fg_home + "/*.log", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/cache/*");
|
SGPath::addAllowedPathPattern(fg_home + "/cache/*", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/Export/*");
|
SGPath::addAllowedPathPattern(fg_home + "/Export/*", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/state/*.xml");
|
SGPath::addAllowedPathPattern(fg_home + "/state/*.xml", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/aircraft-data/*.xml");
|
SGPath::addAllowedPathPattern(fg_home + "/aircraft-data/*.xml", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/Wildfire/*.xml");
|
SGPath::addAllowedPathPattern(fg_home + "/Wildfire/*.xml", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/runtime-jetways/*.xml");
|
SGPath::addAllowedPathPattern(fg_home + "/runtime-jetways/*.xml", true);
|
||||||
write_allowed_paths.push_back(fg_home + "/Input/Joysticks/*.xml");
|
SGPath::addAllowedPathPattern(fg_home + "/Input/Joysticks/*.xml", true);
|
||||||
|
|
||||||
// Check that it works
|
// Check that it works
|
||||||
std::string homePath = globals->get_fg_home().utf8Str();
|
const std::string homePath = globals->get_fg_home().utf8Str();
|
||||||
if(!fgValidatePath(homePath + "/../no.log",true).isNull() ||
|
if (! SGPath(homePath + "/../no.log").validate(true).isNull() ||
|
||||||
!fgValidatePath(homePath + "/no.logt",true).isNull() ||
|
! SGPath(homePath + "/no.logt").validate(true).isNull() ||
|
||||||
!fgValidatePath(homePath + "/nolog",true).isNull() ||
|
! SGPath(homePath + "/nolog").validate(true).isNull() ||
|
||||||
!fgValidatePath(homePath + "no.log",true).isNull() ||
|
! SGPath(homePath + "no.log").validate(true).isNull() ||
|
||||||
!fgValidatePath(homePath + "\\..\\no.log",false).isNull() ||
|
! SGPath(homePath + "\\..\\no.log").validate(false).isNull() ||
|
||||||
fgValidatePath(homePath + "/aircraft-data/yes..xml",true).isNull() ||
|
SGPath(homePath + "/aircraft-data/yes..xml").validate(true).isNull() ||
|
||||||
fgValidatePath(homePath + "/.\\yes.bmp",false).isNull()) {
|
SGPath(homePath + "/.\\yes.bmp").validate(false).isNull()) {
|
||||||
flightgear::fatalMessageBoxThenExit(
|
flightgear::fatalMessageBoxThenExit(
|
||||||
"Nasal initialization error",
|
"Nasal initialization error",
|
||||||
"The FG_HOME directory must not be inside any of the FG_ROOT, "
|
"The FG_HOME directory must not be inside any of the FG_ROOT, "
|
||||||
|
@ -139,46 +136,6 @@ void fgInitAllowedPaths()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether Nasal is allowed to access a path
|
|
||||||
* Warning: because this always (not just on Windows) treats both \ and /
|
|
||||||
* as path separators, and accepts relative paths (check-to-use race if
|
|
||||||
* the current directory changes),
|
|
||||||
* always use the returned path not the original one
|
|
||||||
*/
|
|
||||||
SGPath fgValidatePath (const SGPath& path, bool write)
|
|
||||||
{
|
|
||||||
// Normalize the path (prevents ../../.. or symlink trickery)
|
|
||||||
std::string normed_path = path.realpath().utf8Str();
|
|
||||||
|
|
||||||
const string_list& allowed_paths(write ? write_allowed_paths : read_allowed_paths);
|
|
||||||
size_t star_pos;
|
|
||||||
|
|
||||||
// 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 SGPath::fromUtf8(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 SGPath::fromUtf8(normed_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no match found
|
|
||||||
return SGPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string generateAuthorsText(SGPropertyNode* authors)
|
std::string generateAuthorsText(SGPropertyNode* authors)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
|
@ -37,20 +37,7 @@
|
||||||
double fgGetLowPass (double current, double target, double timeratio);
|
double fgGetLowPass (double current, double target, double timeratio);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File access control, used by Nasal and fgcommands.
|
* Set the read and write lists of allowed paths patterns for SGPath::validate()
|
||||||
* @param path Path to be validated
|
|
||||||
* @param write True for write operations and false for read operations.
|
|
||||||
* @return The validated path on success or empty if access denied.
|
|
||||||
*
|
|
||||||
* Warning: because this always (not just on Windows) treats both \ and /
|
|
||||||
* as path separators, and accepts relative paths (check-to-use race if
|
|
||||||
* the current directory changes),
|
|
||||||
* always use the returned path not the original one
|
|
||||||
*/
|
|
||||||
SGPath fgValidatePath(const SGPath& path, bool write);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set allowed paths for fgValidatePath
|
|
||||||
*/
|
*/
|
||||||
void fgInitAllowedPaths();
|
void fgInitAllowedPaths();
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include <Autopilot/route_mgr.hxx>
|
#include <Autopilot/route_mgr.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <Navaids/FlightPlan.hxx>
|
#include <Navaids/FlightPlan.hxx>
|
||||||
#include <Navaids/NavDataCache.hxx>
|
#include <Navaids/NavDataCache.hxx>
|
||||||
#include <Navaids/airways.hxx>
|
#include <Navaids/airways.hxx>
|
||||||
|
@ -1930,8 +1929,8 @@ static naRef f_flightplan_save(naContext c, naRef me, int argc, naRef* args)
|
||||||
naRuntimeError(c, "flightplan.save, no file path argument");
|
naRuntimeError(c, "flightplan.save, no file path argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPath raw_path(naStr_data(args[0]));
|
const SGPath raw_path(naStr_data(args[0]));
|
||||||
SGPath validated_path = fgValidatePath(raw_path, true);
|
const SGPath validated_path = SGPath(raw_path).validate(true);
|
||||||
if (validated_path.isNull()) {
|
if (validated_path.isNull()) {
|
||||||
naRuntimeError(c, "flightplan.save, writing to path is not permitted");
|
naRuntimeError(c, "flightplan.save, writing to path is not permitted");
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "NasalHTTP.hxx"
|
#include "NasalHTTP.hxx"
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <Network/HTTPClient.hxx>
|
#include <Network/HTTPClient.hxx>
|
||||||
|
|
||||||
#include <simgear/io/HTTPFileRequest.hxx>
|
#include <simgear/io/HTTPFileRequest.hxx>
|
||||||
|
@ -55,7 +54,7 @@ static naRef f_http_save(const nasal::CallContext& ctx)
|
||||||
|
|
||||||
// Check for write access to target file
|
// Check for write access to target file
|
||||||
const std::string filename = ctx.requireArg<std::string>(1);
|
const std::string filename = ctx.requireArg<std::string>(1);
|
||||||
const SGPath validated_path = fgValidatePath(filename, true);
|
const SGPath validated_path = SGPath(filename).validate(true);
|
||||||
|
|
||||||
if( validated_path.isNull() )
|
if( validated_path.isNull() )
|
||||||
ctx.runtimeError("Access denied: can not write to %s", filename.c_str());
|
ctx.runtimeError("Access denied: can not write to %s", filename.c_str());
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "NasalSGPath.hxx"
|
#include "NasalSGPath.hxx"
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||||
|
@ -42,8 +41,8 @@ SGPath::Permissions checkIORules(const SGPath& path)
|
||||||
"realpath() to make a path absolute)");
|
"realpath() to make a path absolute)");
|
||||||
}
|
}
|
||||||
|
|
||||||
perm.read = path.isAbsolute() && !fgValidatePath(path, false).isNull();
|
perm.read = path.isAbsolute() && !SGPath(path).validate(false).isNull();
|
||||||
perm.write = path.isAbsolute() && !fgValidatePath(path, true ).isNull();
|
perm.write = path.isAbsolute() && !SGPath(path).validate(true).isNull();
|
||||||
|
|
||||||
return perm;
|
return perm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@
|
||||||
#include "NasalUnitTesting.hxx"
|
#include "NasalUnitTesting.hxx"
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/util.hxx>
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/sentryIntegration.hxx>
|
#include <Main/sentryIntegration.hxx>
|
||||||
|
|
||||||
|
@ -738,7 +737,7 @@ static naRef f_directory(naContext c, naRef me, int argc, naRef* args)
|
||||||
if(argc != 1 || !naIsString(args[0]))
|
if(argc != 1 || !naIsString(args[0]))
|
||||||
naRuntimeError(c, "bad arguments to directory()");
|
naRuntimeError(c, "bad arguments to directory()");
|
||||||
|
|
||||||
SGPath dirname = fgValidatePath(SGPath::fromUtf8(naStr_data(args[0])), false);
|
SGPath dirname = SGPath::fromUtf8(naStr_data(args[0])).validate(false);
|
||||||
if(dirname.isNull()) {
|
if(dirname.isNull()) {
|
||||||
SG_LOG(SG_NASAL, SG_ALERT, "directory(): listing '" <<
|
SG_LOG(SG_NASAL, SG_ALERT, "directory(): listing '" <<
|
||||||
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
||||||
|
@ -853,7 +852,7 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
||||||
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
||||||
if(!naStr_data(file)) naRuntimeError(c, "bad argument to open()");
|
if(!naStr_data(file)) naRuntimeError(c, "bad argument to open()");
|
||||||
const char* modestr = naStr_data(mode) ? naStr_data(mode) : "rb";
|
const char* modestr = naStr_data(mode) ? naStr_data(mode) : "rb";
|
||||||
SGPath filename = fgValidatePath(SGPath::fromUtf8(naStr_data(file)),
|
const SGPath filename = SGPath::fromUtf8(naStr_data(file)).validate(
|
||||||
strcmp(modestr, "rb") && strcmp(modestr, "r"));
|
strcmp(modestr, "rb") && strcmp(modestr, "r"));
|
||||||
if(filename.isNull()) {
|
if(filename.isNull()) {
|
||||||
SG_LOG(SG_NASAL, SG_ALERT, "open(): reading/writing '" <<
|
SG_LOG(SG_NASAL, SG_ALERT, "open(): reading/writing '" <<
|
||||||
|
@ -897,7 +896,7 @@ static naRef f_custom_stat(naContext ctx, naRef me, int argc, naRef* args)
|
||||||
return naNil();
|
return naNil();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SGPath filename = fgValidatePath(path, false );
|
const SGPath filename = SGPath(path).validate(false);
|
||||||
if (filename.isNull()) {
|
if (filename.isNull()) {
|
||||||
SG_LOG(SG_NASAL, SG_ALERT, "stat(): reading '" <<
|
SG_LOG(SG_NASAL, SG_ALERT, "stat(): reading '" <<
|
||||||
naStr_data(pathArg) << "' denied (unauthorized directory - authorization"
|
naStr_data(pathArg) << "' denied (unauthorized directory - authorization"
|
||||||
|
@ -948,7 +947,7 @@ static naRef f_parsexml(naContext c, naRef me, int argc, naRef* args)
|
||||||
if(!(naIsNil(args[i]) || naIsFunc(args[i])))
|
if(!(naIsNil(args[i]) || naIsFunc(args[i])))
|
||||||
naRuntimeError(c, "parsexml(): callback argument not a function");
|
naRuntimeError(c, "parsexml(): callback argument not a function");
|
||||||
|
|
||||||
SGPath file = fgValidatePath(SGPath::fromUtf8(naStr_data(args[0])), false);
|
const SGPath file = SGPath::fromUtf8(naStr_data(args[0])).validate(false);
|
||||||
if(file.isNull()) {
|
if(file.isNull()) {
|
||||||
SG_LOG(SG_NASAL, SG_ALERT, "parsexml(): reading '" <<
|
SG_LOG(SG_NASAL, SG_ALERT, "parsexml(): reading '" <<
|
||||||
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
||||||
|
|
Loading…
Reference in a new issue