Capabilities can be tracked with continuation marks. For a language to
grant a subset of capabilities to a required module, you can do something
like contract-in that will wrap identifiers with a with-continuation-marks
capability restriction. The tricky part becomes how to make all I/O
subsystems etc. actually consult and respect the capabilities that are
marked on the continuation. That will take a really invasive change to the
runtime, or a flawed approach of a wrapper language around #%kernel such
that everything that builds on top of it respects capabilities.
Unfortunately we can't treat existing modules like functors for which we
can replace the underlying #%kernel.

On Sun, Jul 14, 2019 at 10:25 AM Christopher Lemmer Webber <
cweb...@dustycloud.org> wrote:

> Every day the threats facing our computing environments are getting
> worse.  Recent incidents in both gems and npm have shown modules
> exfiltrating information from developers' machines or production
> servers.  It is likely that soon package managers will also be targeted
> to install cryptolockers to attack developers' machines, or worse,
> install backdoors that allow an attacker to perform arbitrary execution.
> How can we make Racket not only a fun and fulfilling development, but
> also a safe one?
>
> Thankfully, Jonathan Rees did the kind work of laying out the recipe for
> dramatically improved safety over two decades ago:
>
>   http://mumble.net/~jar/pubs/secureos/secureos.html
>
> It turns out that the lambda calculus already provides the fundamental
> layer of security we need; code can only perform actions it has
> references to.  This is called "object capability (ocap) security";
> a decent (ok, I'm biased) intro to the ideas can be found on this
> podcast episode if you are interested:
>
>
> https://librelounge.org/episodes/episode-13-object-capabilities-with-kate-sills.html
>
> Racket already has most of the pieces in place; we just need to add one
> more thing.  Consider and contrast the following scenarios:
>
> Conventional Racket scenario:
>
>   ;; Runs a game of solitaire.
>   ;; Also has access to your entire filesystem, can secretly exfiltrate
>   ;; data or install backdoors, etc etc.
>   (solitaire)
>
> A more desirable scenario:
>
>   ;; Runs a game of solitaire.
>   ;; *Only* has access to a stream of input when the window is active,
>   ;; the ability to draw to a *specific* window on the screen, the
>   ;; ability to read/write from a single file on disk, the save file.
>   (solitaire get-input
>              display-graphics-to-window
>              save-file-access)
>
> Now the amount of damage that solitiare can perform is significantly
> curtailed.  It can perhaps display images we would not like to see
> or write nonsense to its save file, but it cannot do anything else.
> (We could also put limits in the save-file-access procedure on how
> large of a file it is allowed to write, if we were worried about that.)
>
> The key idea here is that authority flows through the system the same
> way that data naturally flows through a program.  You simply don't have
> more access than what you allowed to flow through.
>
> So what is necessary to make Racket ocap-secure?  The primary problem is
> the assumption of "require", that any module can "reach out" and gain
> access to anything it likes, be it network access or file access or etc.
>
> What I would like instead is to allow modules to be "granted" access.
> The idea is in fact the same as with the solitaire-as-procedure solution
> above: modules gain access not by reaching out and grabbing whatever
> they want, but by being "handed" access.  Imagine your module as one big
> procedure where we pass in access to other modules/values/macros and
> you'll get the idea.
>
>
>
> #+BEGIN_SRC racket
>   #lang dungeon
>
>   ; passed in, already fully "empowered"
>   (require match
>            graphics-tools
>            keyboard-tools
>            ;; the parent module must trust us a lot, they gave us full
>            ;; filesystem access!
>            general-file-io
>            ;; solitaire needs picture constructors to generate graphics
>            (empower solitaire graphics-tools))
>
>   (provide run-solitaire)
>
>   (define (get-input input-source)
>     ...)
>
>   (define (display-graphics-to-window ...)
>     ...)
>
>   (define (make-save-file-access filename)
>     (match-lambda
>       [(list 'read) (call-with-input-file filename port->bytes)]
>       [(list 'write bytes)
>        (call-with-output-file filename
>          (lambda (p)
>             (write-bytes bytes p))
>          #:exists 'replace)]))
>
>
>   (define (run-solitaire [save-file "~/.racket-solitaire"])
>     (solitaire get-input display-graphics-to-window
>                (make-save-file-access save-file)))
> #+END_SRC
>
> I've handwaved over a couple of things, but this module shouldn't be
> afraid that the solitaire procedure that comes from the empowered
> solitaire module has access to dangerous things such as the full
> filesystem (even though the importer of *this* module trusted it to have
> full filesystem access), and neither module has network access.
>
> I don't know how to build this fully; I know that:
>  - we need code inspectors to prevent evil hygeine-breaking, but good
>    news we have that
>  - I need a way to make *something like require* work, but where the
>    import-er is able to very explicitly pass in which modules are
>    allowed.  This seems to mean something *like* controlling the module
>    registry.  Note that this also means that the names of the modules
>    being imported aren't from a "global registry" anymore, it's the
>    names that the empowering-module provided.
>
> There's an alternative, which is the emaker / frozen realms approach.
> This approach actually instead gives you an extremely minimal base
> syntax that *cannot be extended*.  No new macros.  Instead, the module
> that is imported wakes up in a cold world of just a few primitives... no
> mutable state, very few authenticated things, etc.  The module then
> returns a function that does the interesting things: we can pass in
> arguments to get out the "interesting" things that the module can
> provide.  You are mostly left with the cold world of lambda and a few
> carefully chosen macros.
>
> But that's kind of sad to throw away macros, imo.  I'm not sure the
> racket community will be happy enough to use it.  I'm not sure I would
> be.
>
> So, how to build this?  It doesn't seem that there's a way to control
> the module registry being used in a require-ing context.  But maybe
> there's something else.
>
> Thoughts, or solutions, welcome.
>  - Chris
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/87y310r3b1.fsf%40dustycloud.org
> .
> For more options, visit https://groups.google.com/d/optout.
>


-- 
-Dionna Glaze, PhD (she/her)

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAAH4kHaBTMSD6GZ3Nh7v_fb7iq7Lqn3fsm_LeWDdsJ6ETngtSQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to