1
0
Fork 0

Nasal: remove obsolete io.nas security

This has been superseded by the C++-level fgValidatePath
This commit is contained in:
Rebecca N. Palmer 2015-11-22 11:22:22 +00:00
parent ece79a7aed
commit 45c3eeb9ad
3 changed files with 0 additions and 217 deletions

View file

@ -1,42 +0,0 @@
# This file defines which file paths can be opened for reading and/or
# writing using Nasal's io.open() and parsexml() functions, as well as
# the fgcommands load, save, loadxml, and savexml. The evaluation code
# can be found in $FG_ROOT/Nasal/io.nas.
#
# Empty lines and lines starting with '#' are ignored. All other entries
# must be of the form
#
# {READ|WRITE} {ALLOW|DENY} <path-pattern>
#
# whereby fields must be separated by exactly one space. The pattern must
# not be quoted and may contain spaces. If a pattern starts with $FG_ROOT/
# or $FG_HOME/, then these parts are replaced by the respective system
# paths. See $FG_ROOT/Nasal/string.nas for the pattern syntax.
#
# Entries are considered from top down. If no entry matches, then file
# access is denied. A local rules file $FG_HOME/Nasal/IOrules using the
# same syntax takes precedence over this file. The default rules that
# apply if there's no Nasal/IOrules file at all, or there are no rules
# defined in it are equivalent to this:
#
# READ DENY *
# WRITE DENY *
#
# Read and write access to Nasal/IOrules files, however, is *always*
# prohibited and not configurable!
READ ALLOW $FG_ROOT/*
READ ALLOW $FG_HOME/*
READ ALLOW $FG_AIRCRAFT/*
WRITE ALLOW /tmp/*.xml
WRITE ALLOW $FG_HOME/*.sav
WRITE ALLOW $FG_HOME/*.log
WRITE ALLOW $FG_HOME/cache/*
WRITE ALLOW $FG_HOME/Export/*
WRITE ALLOW $FG_HOME/state/*.xml
WRITE ALLOW $FG_HOME/aircraft-data/*.xml
WRITE ALLOW $FG_HOME/Wildfire/*.xml
WRITE ALLOW $FG_HOME/runtime-jetways/*.xml
WRITE ALLOW $FG_HOME/Input/Joysticks/*.xml

View file

@ -277,150 +277,3 @@ var writexml = func(path, node, indent = "\t", prefix = "___") {
die("writexml(): tree has more than one root node");
}
# Redefine io.open() such that files can only be opened under authorized directories.
#
_setlistener("/sim/signals/nasal-dir-initialized", func {
# read IO rules
var root = string.normpath(getprop("/sim/fg-root"));
var home = string.normpath(getprop("/sim/fg-home"));
var config = "Nasal/IOrules";
var rules_file = nil;
var read_rules = [];
var write_rules = [];
var load_rules = func(path) {
if (stat(path) == nil)
return nil;
printlog("info", "using io.open() rules from ", path);
read_rules = [];
write_rules = [];
var file = open(path, "r");
for (var no = 1; (var line = readln(file)) != nil; no += 1) {
if (!size(line) or line[0] == `#`)
continue;
var f = split(" ", line);
if (size(f) < 3 or f[0] != "READ" and f[0] != "WRITE" or f[1] != "DENY" and f[1] != "ALLOW") {
printlog("alert", "ERROR: invalid io.open() rule in ", path, ", line ", no, ": ", line);
read_rules = write_rules = [];
break;
}
var pattern = f[2];
foreach (var p; subvec(f, 3))
pattern ~= " " ~ p;
var rules = f[0] == "READ" ? read_rules : write_rules;
var allow = (f[1] == "ALLOW");
if (substr(pattern, 0, 13) == "$FG_AIRCRAFT/") {
var p = substr(pattern, 13);
var sim = props.globals.getNode("/sim");
foreach (var c; sim.getChildren("fg-aircraft")) {
pattern = string.normpath(c.getValue()) ~ "/" ~ p;
append(rules, [pattern, allow]);
printlog("info", "IORules: appending ", pattern);
}
} elsif (substr(pattern, 0, 12) == "$FG_SCENERY/") {
var p = substr(pattern, 12);
var sim = props.globals.getNode("/sim");
foreach (var c; sim.getChildren("fg-scenery")) {
pattern = string.normpath(c.getValue()) ~ "/" ~ p;
append(rules, [pattern, allow]);
printlog("info", "IORules: appending ", pattern);
}
} else {
if (substr(pattern, 0, 9) == "$FG_ROOT/")
pattern = root ~ "/" ~ substr(pattern, 9);
elsif (substr(pattern, 0, 9) == "$FG_HOME/")
pattern = home ~ "/" ~ substr(pattern, 9);
append(rules, [pattern, allow]);
printlog("info", "IORules: appending ", pattern);
}
}
close(file);
return path;
}
# catch exceptions so that a die() doesn't ruin everything
var rules_file = call(func load_rules(home ~ "/" ~ config)
or load_rules(root ~ "/" ~ config), nil, var err = []);
if (size(err)) {
debug.printerror(err);
read_rules = write_rules = [];
}
read_rules = [["*/" ~ config, 0]] ~ read_rules;
write_rules = [["*/" ~ config, 0]] ~ write_rules;
if (__.log_level <= 3) {
print("IOrules/READ: ", debug.string(read_rules));
print("IOrules/WRITE: ", debug.string(write_rules));
}
# make safe, local copies
var setValue = props._setValue;
var getValue = props._getValue;
var normpath = string.normpath;
var match = string.match;
var caller = caller;
var die = die;
# validators
var valid = func(path, rules) {
var fpath = normpath(path);
foreach (var d; rules)
if (match(fpath, d[0]))
return d[1] ? fpath : nil;
return nil;
}
var read_validator = func(n) setValue(n, [valid(getValue(n, []), read_rules) or ""]);
var write_validator = func(n) setValue(n, [valid(getValue(n, []), write_rules) or ""]);
# validation listeners for load[xml]/save[xml]/parsexml() (see utils.cxx:fgValidatePath)
var n = props.globals.getNode("/sim/paths/validate", 1).removeAllChildren();
var rval = _setlistener(n.getNode("read", 1)._g, read_validator);
var wval = _setlistener(n.getNode("write", 1)._g, write_validator);
# wrap removelistener
globals.removelistener = var remove_listener = (func {
var _removelistener = globals.removelistener;
func(n) {
if (n != rval and n != wval)
return _removelistener(n);
die("removelistener(): removal of protected listener #'" ~ n ~ "' denied (unauthorized access)\n ");
}
})();
# wrap io.open()
io.open = var io_open = (func {
var _open = io.open;
func(path, mode = "rb") {
var rules = write_rules;
if (mode == "r" or mode == "rb" or mode == "br")
rules = read_rules;
if (var vpath = valid(path, rules))
return _open(vpath, mode);
die("io.open(): opening file '" ~ path ~ "' denied (unauthorized access)\n ");
}
})();
# wrap closure() to prevent tampering with security related functions
var thislistener = caller(0)[1];
globals.closure = (func {
var _closure = globals.closure;
func(fn, level = 0) {
var thisfunction = caller(0)[1];
if (fn != thislistener and fn != io_open and fn != thisfunction
and fn != read_validator and fn != write_validator
and fn != remove_listener)
return _closure(fn, level);
die("closure(): query denied (unauthorized access)\n ");
}
})();
});

View file

@ -76,32 +76,6 @@ var icmp = func(a, b) cmp(lc(a), lc(b));
var imatch = func(a, b) match(lc(a), lc(b));
##
# Functions that are used in the IO security code (io.nas) are defined in a
# closure that holds safe copies of system functions. Later manipulation of
# append(), pop() etc. doesn't affect them. Of course, any security code
# must itself store safe copies of these tamper-proof functions before user
# code can redefine them, and the closure() command must be made inaccessible.
##
var match = nil;
var normpath = nil;
var join = nil;
var replace = nil;
(func {
var append = append;
var caller = caller;
var pop = pop;
var setsize = setsize;
var size = size;
var split = split;
var substr = substr;
var subvec = subvec;
##
# check if string <str> matches shell style pattern <patt>
#
@ -238,8 +212,6 @@ replace = func(str, old, new) {
return join(new, split(old, str));
}
})(); # end tamper-proof environment
##
# Get a function out of a string template for fast insertion of template