The Philosophy of Security in Rebol


At its core, Rebol has the idea that any PATH! or WORD! might be a function, and it might wind up dispatching it. There is no special syntax for function calls or delimiting. Reading a line of code like:

foo baz bar/:mumble frotz

…could be pretty much anything.

>> foo: 10
>> baz: 20
>> bar: [asdf ghijk 30 lmno pqrs]
>> mumble: 3
>> frotz: 40
>> reduce [foo baz bar/:mumble frotz]
[10 20 30 40]

>> foo: func [a b c] [a + b + c]
>> reduce [foo baz bar/:mumble frotz]

>> bar: object [something: does [print "all your base!" 1000]]
>> mumble: 'something
>> reduce [foo baz bar/:mumble frotz]
all your base!
== [1060]

Love it or hate it, this idea is central to the language. As per the infamous “deep lake”, this is the freeform aspect. You can create more restricted dialects if you want to…BUT the moment you invoke the evaluator (via DO, REDUCE, PRINT, COMPOSE etc.) you’re opening a can of worms.

I’d say that if you run untrusted code in Rebol, you’re pretty much dancing with the devil. So the better way to think about security is perhaps more in terms of what the executable is allowed to do in terms of its sandbox, it’s very difficult to “secure” against hostile libraries.

Ren-C has tried to take patterns of “defense” seen authored by BrianH and others and find better ways. For instance, he noticed that it was possible to slip values for locals in and fool system routines…e.g.

do-thing: func [filename /local x] [
    if has-property filename [
        x: filename
    if x [delete x]

He noticed that someone could call do-thing/local %irrelevant.txt %important-file.txt. Since Rebol treated /local as any refinement, that was not disallowed. So he’d “bulletproof” the routines by purposefully blanking arguments to the local refinement, to ensure no leakage occurred.

Ren-C has tried, where possible, to take patterns like this and mitigate them. So for instance, do-thing: func [filename <local> x] [...] mechanically ensures that x will be not set when do-thing runs. And if you choose to call your refinement /local that follows the rules of refinements, so time/local is legitimate.

Noticing these patterns has led to other, more potentially questionable choices. See for instance, “Should function arguments to functions be disallowed by default”. Is this a help or a hindrance? We have a bit of time experimenting with it, so feedback is welcome… but it’s designed to try and change the balance of needing to write “defensive” routines… in the spirit of thinking a “savvy” coder is supposed to blank locals to dodge them being passed in with the /local refinement.

But, is this closing the barn door after the horse is gone? How do people consider Rebol’s security premise? I’ve given a couple of examples, and I wonder if people have opinions here.

Special Syntax for FOR-EACH/etc. to receive ACTION!s?
"SECURE is disabled"...?

I have never used Rebol 2 security system so can’t comment on that.

But I have used Perl’s Taint mode, where any external input is TAINTED and so will throw a runtime error if used unless that input is UNTAINTED first. Perhaps this is something worth looking at?