
The docs for security guards say this:
> A thread’s current security guard is determined by the current-security-guard parameter. Every security guard has a parent, and a parent’s access procedures are called whenever a child’s access procedures are called. Thus, a thread cannot increase its own access arbitrarily by installing a new guard. The initial security guard enforces no access restrictions other than those enforced by the host platform.

But the following doesn’t raise any security errors:
#lang racket
(define original-guard (current-security-guard))
(define (read-secret)
(file->string "/Users/jackfirth/githubtoken"))
(define (security-guard-deny-files guard)
(define (deny who path actions)
(error who "not allowed access to files"))
(make-security-guard guard deny void))
(read-secret)
(define (call/evil proc)
(parameterize ([current-security-guard original-guard])
(proc)))
(parameterize
([current-security-guard (security-guard-deny-files original-guard)])
(call/evil read-secret))

Am I misunderstanding the purpose of security guards? It seems like installing a security guard guarantees nothing unless a fresh namespace is used too, since any called function could have closed over the original, weaker security guard before you installed the strict one

My imaginary use case is a contract on a function that says it can be called in a context where the current security guard disallows access to files; such a contract doesn’t seem enforceable (by installing a security guard during calls to the function) if the function can just replace the strict guard with a lenient one it got from somewhere else

do security guards assume that you’re using them with racket/sandbox
or something?

After a lot of poking and reading about thread local storage, I got this moving with these instructions, thank you!
As you say, cooperating with 3m GC is going to be another story, and I’m finding that this is harder than I expected due to my inexperience with Windows as well… I guess patience is the name of the game.

security guards are intended for protecting eval-like operations (such as eval
itself or module loading)

@samth Are you thinking of code inspectors? Security guards are for operations like filesystem and network access.

I’m aware of that

@notjack I think the docs should say “by creating a new guard” instead of “by installing a new guard”. If your code captures a lenient guard, then it can perform operations under that old guard the way your code does. After all, if it was able to capture a lenient guard, it could have created a thread (with the same lenient guard) and forwarded operations to that other thread (with the initial guard) to perform instead.

@ryanc hmmm. that would be an improvement to the docs, though I think they ought to go further and point out the implication that any non-dynamically-created module can circumvent a guard installed after module initialization time, since it could have simply captured (current-security-guard)
in a module definition

that’s very subtle and totally changes how I’d imagine using them

@notjack Yes, that’s true. There should probably be a mini-guide on security and sandboxing in Racket. For example, if you’re worried about security guards, you should be just as worried about code inspectors.

like, I was assuming security guards were for enforcing stuff between two modules - not between two namespaces (I think that’s a correct description)

@ryanc I’ve been in a vague state of fear of code inspectors for a long time but don’t actually understand how much power they have, just that they can see into structs sometimes

@notjack the (current-inspector)
parameter controls access to structs, but the (current-code-inspector)
parameter controls things like whether a module is allowed to use the protected exports of the modules it requires.

and that’s related to FFI things right?

and unsafe ops

Yes. For example, if you set the current security guard but not the code inspector, then a module might not be able to call open-input-file
but it could still use the FFI to call the C library’s open
. (And it could unsafely mutate the security guard into one that allows everything, anyway.)

That’s why I think there should be a guide that describes how to turn the individual mechanisms into a security strategy.

hmmm. when would it be a good idea to use security guards + code inspectors without just going all the way and using sandboxes?

maybe if you’re only using dynamic-require
kinds of things instead of full-blown eval
?

I think so, yes… or if for some other reason you want to share the same module registry (and module instances) instead of creating a new one.

I could see doing it with distributed computation between trusted machines - in that case you might assume everyone’s got the same collections so you can send functions in the form of pointers to module exports that other nodes dynamically require

like static pointers in haskell

I have absolutely no idea if that’d actually be faster or safer than eval though

@mflatt Thanks. :slightly_smiling_face:

Am I the only one that always gets an error when opening a new file in DrRacket?

Usually something like: instantiate-linklet: mismatch;
reference to a variable that has the wrong procedure or structure-type shape;
possibly, bytecode file needs re-compile because dependencies changed
name: add-relative-requires!
exporting instance: "/Users/leif/rsrc/scribble/scribble-lib/scribble/srcdoc.rkt"
importing instance: "/Users/leif/rsrc/gui/gui-lib/framework/preferences.rkt"
Module Language: invalid language specification in: scratch

(And I have recompiled)

@mflatt would it be possible to point me in the direction towards the solution to this issue? or do you think it’s too subtle for me to get all the pieces right? https://github.com/racket/racket/issues/2062

I think it’s pretty clear that some expansion context(s) need def-ctx-scopes
to be a box, but I’m not confident enough about when to call accumulate-def-ctx-scopes
.

@lexi.lambda I don’t know offhand. I can take a look, but probably not today (and I’m only half-way, probably, in sorting out the other problem you ran into yesterday)

Okay, that’s alright. I just figured I’d ask in case it was something I could deal with to relieve you of some work. If it wouldn’t make it any easier on you, then there isn’t much point, but I’ll definitely look at your fix once you do get to it, whenever that may be.

@mflatt @ryanc When I start up the macro stepper I’m getting an internal error:
Internal error:
derivation-parser: error on token #3292: <syntax-error, #(struct:exn:fail "expand: namespace mismatch; cannot locate module instance\n module: #<module-path-index:\"private/lang.rkt\" \"base.rkt\" + 'lang[2010586]>\n use phase: 0\n definition phase: 0\n for identifier: #<syntax:Users/leif/vsrc/idmt/editor/private/lang.rkt:103:64 from-editor>" #<continuation-mark-set>)>

```

derivation-parser: error on token #3292: <syntax-error, #(struct:exn:fail "expand: namespace mismatch; cannot locate module instance\n module: #<module-path-index:\"private/lang.rkt\" \"base.rkt\" + 'lang[2010586]>\n use phase: 0\n definition phase: 0\n for identifier: #<syntax:Users/leif/vsrc/idmt/editor/private/lang.rkt:103:64 from-editor>" #<continuation-mark-set>)>
context...:
/Users/leif/rsrc/parser-tools/parser-tools-lib/parser-tools/yacc.rkt:347:16: parsing-loop
.../more-scheme.rkt:261:28
/Users/leif/rsrc/macro-debugger/macro-debugger/macro-debugger/view/term-record.rkt:123:4: recache-deriv! method in term-record%
/Users/leif/rsrc/macro-debugger/macro-debugger/macro-debugger/view/term-record.rkt:63:16: get-deriv-hidden? method in term-record%
/Users/leif/rsrc/macro-debugger/macro-debugger/macro-debugger/view/stepper.rkt:70:24
/Users/leif/rsrc/gui/gui-lib/mred/private/wx/common/queue.rkt:428:6
/Users/leif/rsrc/gui/gui-lib/mred/private/wx/common/queue.rkt:479:32
/Users/leif/rsrc/gui/gui-lib/mred/private/wx/common/queue.rkt:627:3


With this attached debug snippet.

Would either of you have any idea what the problem here might be?

For what its worth, I also get an error when expanding without the macro stepper, which is: expand: namespace mismatch; cannot locate module instance
module: #<module-path-index:"private/lang.rkt" "base.rkt" + 'lang[6832]>
use phase: 0
definition phase: 0
for identifier: #<syntax:private/lang.rkt:103:64 from-editor>
compilation context...:
/Users/leif/v/idmt/editor/lang.rkt
context...:
binding->module-instance
binding-lookup50
loop
/Users/leif/racket/racket/collects/racket/require-transform.rkt:266:2: expand-import
/Users/leif/racket/racket/collects/racket/private/reqprov.rkt:266:21: try-next
/Users/leif/racket/racket/collects/racket/private/reqprov.rkt:243:2: require
apply-transformer-in-context
dispatch-transformer41
do-local-expand58
/Users/leif/racket/racket/collects/syntax/wrap-modbeg.rkt:46:4: do-wrapping-module-begin
apply-transformer-in-context
dispatch-transformer41
loop
finish
[repeats 3 more times]
pass-1-and-2-loop
...

So there clearly is a bug in my macro, but it also appears that there is an internal macro stepper error as well.

@leif Your example is 25,000 lines? :slightly_smiling_face:

@greg lol, nah, that’s the macro stepper’s debug output.

@mflatt Maybe a simpler question, what does a +
in a module-path-index mean, as in: #<module-path-index:"private/lang.rkt" "base.rkt" + 'lang[6832]>
.

@leif Didn’t mean to sound critical. I figured I’d try debug.rkt
in Racket 6.10 to see how it worked, there. And wasn’t sure what to do with it. Anyway got a read
error due to the #<
in the prints of the opaque structs. ¯_(ツ)_/¯

lol, ya.

Nah, I didn’t feel criticized.

Like, if that were a code snippet, it would be useless.

(Also out of habit I hit C-A-q in Emacs to indent it, and was horrified to see “indenting region x% done…” message and thought I had a racket-mode bug to fix.)

But nah, its just debug diagnostic data. Which…I have no idea how to interperate. :slightly_smiling_face:

LOLOLOL

I am happy to try eval
-ing anything. Why I have so many worms.

(eval ’(totally not a worm))