Nasal security: add --allow-nasal-read, warn on non-Nasal-readable
Terrasync, prepare for allowing --download-dir Add unmangled_fg_scenery
This commit is contained in:
parent
c4f584dadf
commit
31cb65e8d9
6 changed files with 76 additions and 24 deletions
|
@ -1152,7 +1152,7 @@ do_load_xml_to_proptree(const SGPropertyNode * arg)
|
|||
SGPath validated_path = fgValidatePath(file, false);
|
||||
if (validated_path.isNull()) {
|
||||
SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file << "' denied "
|
||||
"(unauthorized directory - authorization no longer follows symlinks; to authorize reading additional directories, add them to --fg-aircraft)");
|
||||
"(unauthorized directory - authorization no longer follows symlinks; to authorize reading additional directories, pass them to --allow-nasal-read)");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -373,8 +373,9 @@ void FGGlobals::append_fg_scenery (const SGPath &path, bool secure)
|
|||
// out, such that all three dirs are added. Unfortunately there's
|
||||
// no information as to why the change was made.
|
||||
fg_scenery.push_back(abspath);
|
||||
unmangled_fg_scenery.push_back(abspath);
|
||||
if (secure) {
|
||||
secure_fg_scenery.push_back(abspath);
|
||||
extra_read_allowed_paths.push_back(abspath);
|
||||
}
|
||||
|
||||
if (terrainDir.exists()) {
|
||||
|
@ -399,10 +400,20 @@ void FGGlobals::append_fg_scenery (const SGPath &path, bool secure)
|
|||
n->setAttribute(SGPropertyNode::PRESERVE, true);
|
||||
}
|
||||
|
||||
void FGGlobals::append_read_allowed_paths(const SGPath &path)
|
||||
{
|
||||
SGPath abspath(path.realpath());
|
||||
if (!abspath.exists()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "read-allowed path not found:" << abspath);
|
||||
return;
|
||||
}
|
||||
extra_read_allowed_paths.push_back(abspath);
|
||||
}
|
||||
|
||||
void FGGlobals::clear_fg_scenery()
|
||||
{
|
||||
fg_scenery.clear();
|
||||
secure_fg_scenery.clear();
|
||||
unmangled_fg_scenery.clear();
|
||||
fgGetNode("/sim", true)->removeChildren("fg-scenery");
|
||||
|
||||
}
|
||||
|
|
|
@ -107,7 +107,9 @@ private:
|
|||
|
||||
// Roots of FlightGear scenery tree
|
||||
PathList fg_scenery;
|
||||
PathList secure_fg_scenery;
|
||||
PathList unmangled_fg_scenery;
|
||||
// Paths Nasal is allowed to read
|
||||
PathList extra_read_allowed_paths;
|
||||
|
||||
std::string browser;
|
||||
|
||||
|
@ -218,7 +220,8 @@ public:
|
|||
void set_fg_home (const SGPath &home);
|
||||
|
||||
const PathList &get_fg_scenery () const { return fg_scenery; }
|
||||
const PathList &get_secure_fg_scenery () const { return secure_fg_scenery; }
|
||||
const PathList &get_unmangled_fg_scenery () const { return unmangled_fg_scenery; }
|
||||
const PathList &get_extra_read_allowed_paths () const { return extra_read_allowed_paths; }
|
||||
/**
|
||||
* Add a scenery directory
|
||||
*
|
||||
|
@ -232,6 +235,16 @@ public:
|
|||
void append_fg_scenery (const PathList &scenery, bool secure = false);
|
||||
|
||||
void clear_fg_scenery();
|
||||
|
||||
/**
|
||||
* Allow Nasal to read a path
|
||||
*
|
||||
* To avoid can-read-any-file security holes, do NOT call this on paths
|
||||
* obtained from the property tree or other Nasal-writable places
|
||||
*
|
||||
* Only works during initial load (before fgInitAllowedPaths)
|
||||
*/
|
||||
void append_read_allowed_paths (const SGPath &path);
|
||||
|
||||
/**
|
||||
* specify a path we'll prepend to the aircraft paths list if non-empty.
|
||||
|
|
|
@ -865,6 +865,28 @@ fgOptTerrasyncDir( const char *arg )
|
|||
return FG_OPTIONS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
fgOptDownloadDir( const char *arg )
|
||||
{
|
||||
SGPath p = SGPath::fromLocal8Bit(arg);
|
||||
//globals->append_read_allowed_paths(p);
|
||||
fgSetString("/sim/paths/download-dir", p.utf8Str());
|
||||
return FG_OPTIONS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
fgOptAllowNasalRead( const char *arg )
|
||||
{
|
||||
PathList paths = SGPath::pathsFromLocal8Bit(arg);
|
||||
if(paths.size() == 0) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "--allow-nasal-read requires a list of directories to allow");
|
||||
}
|
||||
for( PathList::const_iterator it = paths.begin(); it != paths.end(); ++it ) {
|
||||
globals->append_read_allowed_paths(*it);
|
||||
}
|
||||
return FG_OPTIONS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
fgOptFov( const char *arg )
|
||||
{
|
||||
|
@ -1629,7 +1651,8 @@ struct OptionDesc {
|
|||
{"disable-terrasync", false, OPTION_BOOL, "/sim/terrasync/enabled", false, "", 0 },
|
||||
{"enable-terrasync", false, OPTION_BOOL, "/sim/terrasync/enabled", true, "", 0 },
|
||||
{"terrasync-dir", true, OPTION_FUNC, "", false, "", fgOptTerrasyncDir },
|
||||
{"download-dir", true, OPTION_STRING, "/sim/paths/download-dir", false, "", 0 },
|
||||
{"download-dir", true, OPTION_FUNC, "", false, "", fgOptDownloadDir },
|
||||
{"allow-nasal-read", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptAllowNasalRead },
|
||||
{"geometry", true, OPTION_FUNC, "", false, "", fgOptGeometry },
|
||||
{"bpp", true, OPTION_FUNC, "", false, "", fgOptBpp },
|
||||
{"units-feet", false, OPTION_STRING, "/sim/startup/units", false, "feet", 0 },
|
||||
|
|
|
@ -92,36 +92,31 @@ void fgInitAllowedPaths()
|
|||
}
|
||||
read_allowed_paths.clear();
|
||||
write_allowed_paths.clear();
|
||||
std::string fg_root = globals->get_fg_root().realpath().utf8Str();
|
||||
std::string fg_home = globals->get_fg_home().realpath().utf8Str();
|
||||
|
||||
read_allowed_paths.push_back(fg_root + "/*");
|
||||
read_allowed_paths.push_back(fg_home + "/*");
|
||||
read_allowed_paths.push_back(fg_root);
|
||||
read_allowed_paths.push_back(fg_home);
|
||||
|
||||
const PathList& aircraft_paths = globals->get_aircraft_paths();
|
||||
const PathList& scenery_paths = globals->get_secure_fg_scenery();
|
||||
const PathList& other_read_paths = globals->get_extra_read_allowed_paths();
|
||||
// not plain fg_scenery, to avoid making
|
||||
// /sim/terrasync/scenery-dir a security hole
|
||||
PathList read_paths = aircraft_paths;
|
||||
read_paths.insert(read_paths.end(), scenery_paths.begin(), scenery_paths.end());
|
||||
read_paths.insert(read_paths.end(), other_read_paths.begin(), other_read_paths.end());
|
||||
read_paths.push_back(globals->get_fg_root());
|
||||
read_paths.push_back(globals->get_fg_home());
|
||||
|
||||
|
||||
for( PathList::const_iterator it = read_paths.begin(); it != read_paths.end(); ++it )
|
||||
for( PathList::const_iterator it = read_paths.begin(); it != read_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->isNull() || fg_root.empty() || fg_home.empty()) {
|
||||
if (it->isNull()) {
|
||||
flightgear::fatalMessageBox("Nasal initialization error",
|
||||
"Empty string in FG_ROOT, FG_HOME, FG_AIRCRAFT or FG_SCENERY",
|
||||
"Empty string in FG_ROOT, FG_HOME, FG_AIRCRAFT, FG_SCENERY or --allow-nasal-read",
|
||||
"or fgInitAllowedPaths() called too early");
|
||||
exit(-1);
|
||||
}
|
||||
read_allowed_paths.push_back(it->realpath().utf8Str() + "/*");
|
||||
read_allowed_paths.push_back(it->realpath().utf8Str());
|
||||
}
|
||||
|
||||
|
||||
std::string fg_home = globals->get_fg_home().realpath().utf8Str();
|
||||
write_allowed_paths.push_back(fg_home + "/*.sav");
|
||||
write_allowed_paths.push_back(fg_home + "/*.log");
|
||||
write_allowed_paths.push_back(fg_home + "/cache/*");
|
||||
|
@ -142,10 +137,20 @@ void fgInitAllowedPaths()
|
|||
fgValidatePath(homePath + "/aircraft-data/yes..xml",true).isNull() ||
|
||||
fgValidatePath(homePath + "/.\\yes.bmp",false).isNull()) {
|
||||
flightgear::fatalMessageBox("Nasal initialization error",
|
||||
"The FG_HOME directory must not be inside any of the FG_ROOT, FG_AIRCRAFT or FG_SCENERY directories",
|
||||
"The FG_HOME directory must not be inside any of the FG_ROOT, FG_AIRCRAFT, FG_SCENERY or --allow-nasal-read directories",
|
||||
"(check that you have not accidentally included an extra :, as an empty part means the current directory)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Warn the user if they have an unreadable Terrasync directory
|
||||
// (can't securely make it readable because Nasal can change /sim/terrasync/scenery-dir)
|
||||
if(fgValidatePath(SGPath::fromUtf8(fgGetString("/sim/terrasync/scenery-dir")),false).isNull()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "You have a non-standard Terrasync directory "
|
||||
<< "set only by /sim/terrasync/scenery-dir. For security reasons, "
|
||||
<< "Nasal scripts are not allowed to read such directories, which "
|
||||
<< "may break some features (e.g. animated jetways). To fix this, "
|
||||
<< "use the launcher's settings, or --terrasync-dir in .fgfsrc");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -582,7 +582,7 @@ static naRef f_directory(naContext c, naRef me, int argc, naRef* args)
|
|||
SG_LOG(SG_NASAL, SG_ALERT, "directory(): listing '" <<
|
||||
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
||||
" no longer follows symlinks; to authorize reading additional "
|
||||
"directories, add them to --fg-aircraft)");
|
||||
"directories, pass them to --allow-nasal-read)");
|
||||
// to avoid breaking dialogs, pretend it doesn't exist rather than erroring out
|
||||
return naNil();
|
||||
}
|
||||
|
@ -689,7 +689,7 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
|||
SG_LOG(SG_NASAL, SG_ALERT, "open(): reading/writing '" <<
|
||||
naStr_data(file) << "' denied (unauthorized directory - authorization"
|
||||
" no longer follows symlinks; to authorize reading additional "
|
||||
"directories, add them to --fg-aircraft)");
|
||||
"directories, pass them to --allow-nasal-read)");
|
||||
naRuntimeError(c, "open(): access denied (unauthorized directory)");
|
||||
return naNil();
|
||||
}
|
||||
|
@ -731,7 +731,7 @@ static naRef f_parsexml(naContext c, naRef me, int argc, naRef* args)
|
|||
SG_LOG(SG_NASAL, SG_ALERT, "parsexml(): reading '" <<
|
||||
naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
|
||||
" no longer follows symlinks; to authorize reading additional "
|
||||
"directories, add them to --fg-aircraft)");
|
||||
"directories, pass them to --allow-nasal-read)");
|
||||
naRuntimeError(c, "parsexml(): access denied (unauthorized directory)");
|
||||
return naNil();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue