A sketch of the security model

0 views
Skip to first unread message

Dan Sugalski

unread,
Apr 13, 2005, 5:01:21 PM4/13/05
to perl6-i...@perl.org
So here's what I was thinking of for Parrot's security and quota
model. (Note that none of this is actually *implemented* yet...)

All security is done on a per-interpreter basis. (really on a
per-thread basis, but since we're one-thread per interpreter it's
essentially the same thing)

QUOTAs are limits on the number of resources or operations that an
interpreter an allocate or perform, either in absolute terms (i.e.
allocate no more than 10M of memory) or relative terms (i.e. can do
only 10 IO operations per second). Quotas are tracked by parrot, and
cover:

* Number of open files
* IO operations/sec
* IO operations total
* Memory allocated
* CPU time consumed
* Threads spawned
* Sub-processes spawned total
* Simultaneous sub-processes

PRIVILEGEs are permissions to do certain things. Parrot will have a
number of privileges it checks before doing dangerous operations, and
user code may also assign and check privileges.

Normally parrot runs with no quotas and no privilege checking. This
is the fastest way to run. Code may at any time enable privilege
and/or quota checking. Once enabled code must have proper privileges
to disable it again.

Each running thread has two sets of privileges -- the active
privileges and the enableable privileges. Active privs are what's
actually in force at the moment, and can be dropped at any time. The
enableable privs are ones that code can turn on. It's possible to
have an active priv that's not in the enableable set, in which case
the current running code is allowed to do something but as soon as
the privilege is dropped it can't be re-enabled.

Additionally, subroutines may be marked as having privileges, which
means that as long as control is inside the sub the priv in question
is enabled. This allows for code that has elevated privs, generally
system-level code.

Continuations, when taken, capture the current set of active and
enableable privs, and when invoked those privs are put into place.
(This is a spot that will require some thought, since there's a
potential for privilege leaks which worries me here) Non-continuation
invokables (subs and methods) maintain the current set of privs, plus
possibly adding the sub-specific privs.

It's actually pretty straightforward, the hard part being the whole
"don't screw up when implementing" thing, along with designing the
base set of privs. Personally I think taking the VMS priv and quota
system as a base is a good way to go -- it's well-respected and
well-tested, and so far as I know theoretically sound. Unix's priv
model's a lot more primitive, and I don't think it's the one to take.
(We could invent our own, but history shows that people who invent
their own security system invent ones that suck, so that looks like
something worth avoiding)

--
Dan

--------------------------------------it's like this-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Aaron Sherman

unread,
Apr 13, 2005, 5:51:52 PM4/13/05
to Dan Sugalski, Perl6 Internals List
On Wed, 2005-04-13 at 17:01, Dan Sugalski wrote:
> So here's what I was thinking of for Parrot's security and quota
> model. (Note that none of this is actually *implemented* yet...)
[...]

> It's actually pretty straightforward, the hard part being the whole
> "don't screw up when implementing" thing, along with designing the
> base set of privs. Personally I think taking the VMS priv and quota
> system as a base is a good way to go -- it's well-respected and
> well-tested, and so far as I know theoretically sound. Unix's priv
> model's a lot more primitive, and I don't think it's the one to take.
> (We could invent our own, but history shows that people who invent
> their own security system invent ones that suck, so that looks like
> something worth avoiding)

VMS at least *is* a priv-based security model, but VMS privs are not
appropriate for parrot on the whole.

That said, it's been 10+ years since I've touched VMS, so pardon as I go
and Google the priv list....

Privs that make sense for Parrot without change:

ALL Allow all privileges.
DETACH Create detached processes.
EXQUOTA Exceed resource quotas.
SETPRV Grant a process any privilege.
SHMEM Create or delete data structures in shared memory.
SYSGBL Create system global sections.
SYSLCK Request locks on system resources.

Privs that make no sense at all for Parrot (as far as I can tell):

ACNT Create a process for which no accounting is performed.
BUGCHK Make bugcheck error log entries.
CMEXEC Change mode to Executive.
CMKRNL Change mode to Kernel.
DIAGNOSE Issue diagnostic I/O requests.
GRPNAM Enter names in the group logical name table.
GRPPRV Allow access to files in the group and system
categories.
MOUNT Issue mount volume I/O requests.
PHY_IO Issue physical I/O requests.
PRMCEB Create permanent common event flag clusters.
PRMGBL Create permanent global clusters.
PSWAPM Change process swap mode.
SHARE Assign a channel to a device.
SYSNAM Enter names in the system logical name table.
TMPMBX Create temporary mailbox devices.
VOLPRO Override protection on a volume.
WORLD Control the execution of any process on the system.

Privs that could make sense, but have different meanings:

ALLSPOOL Allocate spooled devices.
This means you can create new handles
ALTPRI Increase the base execution priority for any process.
change to: Allow QUOTA modification
BYPASS Access resources without regard to UIC protection.
This means ignore my privs and just do it (default)
GROUP Control execution of other processes in the same group.
This is interp-to-interp control (e.g. kill my sibling)
LOG_IO Issue logical I/O requests.
if we assume that this means any handle I/O
NETMBX Create a network device.
This just means "allocate any network resource (e.g. socket)"
OPER Perform system operator functions.
In VMS this was fuzzy, and referred to any operation
that told the OS that it required OPER (like running
certain tools). I'm not sure what this means for
Parrot that BYPASS does not....
PFNMAP Create or delete sections mapped by page frame.
Allocate new PMCs
PRMMBX Create permanent mailbox devices.
Create "special" files of any sort (e.g. POSIX fifo)
SECURITY Perform security-related functions.
?
SYSPRV Access resources as if the process has a system UIC.
?

Privs that do not exist in VMS:

NEWPBC Execute new Parrot Byte Code at run-time
DEBUG Perform operations only appropriate for a debugger
GCDOD Directly manage GC/DOD behavior
NONREL Create I/O handles from non-relative locaters
(e.g. open a rooted path; possibly applicable to
URI interpretation also)
DLOAD Dynamically load binary objects
PLOAD Dynamically load Parrot byte code (bypass NEWPBC)
This allows a PVM to load an existing PBC module and
execute it, but not to create its own PBC at run-time.
More...?

I think it would be easier to start from scratch, personally. I
understand your concerns, but I don't think you run any less risk by
creating a new VM security model out of an OS security model than you do
by creating a new one. They both create many opportunities to make a
mistake.

If you really want to reduce the chances that you'll make a mistake,
swipe the security model from JVM or CLR and start with that. At least
those have been tested in the large, and map closer to what Parrot wants
to do than VMS.

Don't get me wrong. I loved VMS back in the day. It was a pain in the
ass at times, but what isn't. It's just that it's not a VM trying to
execute byte-code... it's an operating system which directly manages
hardware.

--
Aaron Sherman <a...@ajs.com>
Senior Systems Engineer and Toolsmith
"It's the sound of a satellite saying, 'get me down!'" -Shriekback


Michael Walter

unread,
Apr 13, 2005, 10:03:14 PM4/13/05
to Dan Sugalski, perl6-i...@perl.org
Dan,

On 4/13/05, Dan Sugalski <d...@sidhe.org> wrote:
> All security is done on a per-interpreter basis. (really on a
> per-thread basis, but since we're one-thread per interpreter it's
> essentially the same thing)

Just to get me back on track: Does this mean that when you spawn a
thread, a separate interpreter runs in/manages that thread, or
something else?

> Each running thread has two sets of privileges -- the active
> privileges and the enableable privileges. Active privs are what's
> actually in force at the moment, and can be dropped at any time. The
> enableable privs are ones that code can turn on. It's possible to
> have an active priv that's not in the enableable set, in which case
> the current running code is allowed to do something but as soon as
> the privilege is dropped it can't be re-enabled.

How can dropping a privilege for the duration of a (dynamic) scope be
implemented? Does this need to be implemented via a parrot intrinsic,
such as:

without_privs(list_of_privs, code_to_be_run_without_these_privs);

..or is it possible to do so with the primitives you sketched out above?

> Additionally, subroutines may be marked as having privileges, which
> means that as long as control is inside the sub the priv in question
> is enabled. This allows for code that has elevated privs, generally
> system-level code.

Does the code marking a subroutines must have any other privilege than
the one it is marking the subroutine with?

> ... Non-continuation


> invokables (subs and methods) maintain the current set of privs, plus
> possibly adding the sub-specific privs.

Same for closures?

Regards,
Michael

Dan Sugalski

unread,
Apr 14, 2005, 9:11:52 AM4/14/05
to Michael Walter, perl6-i...@perl.org
At 10:03 PM -0400 4/13/05, Michael Walter wrote:
>Dan,
>
>On 4/13/05, Dan Sugalski <d...@sidhe.org> wrote:
>> All security is done on a per-interpreter basis. (really on a
>> per-thread basis, but since we're one-thread per interpreter it's
>> essentially the same thing)
>Just to get me back on track: Does this mean that when you spawn a
>thread, a separate interpreter runs in/manages that thread, or
>something else?

We'd decided that each thread has its own interpreter. Parrot doesn't
get any lighter-weight than an interpreter, since trying to have
multiple threads of control share an interpreter seems to be a good
way to die a horrible death.

> > Each running thread has two sets of privileges -- the active
>> privileges and the enableable privileges. Active privs are what's
>> actually in force at the moment, and can be dropped at any time. The
>> enableable privs are ones that code can turn on. It's possible to
>> have an active priv that's not in the enableable set, in which case
>> the current running code is allowed to do something but as soon as
>> the privilege is dropped it can't be re-enabled.
>
>How can dropping a privilege for the duration of a (dynamic) scope be
>implemented? Does this need to be implemented via a parrot intrinsic,
>such as:
>
> without_privs(list_of_privs, code_to_be_run_without_these_privs);
>
>..or is it possible to do so with the primitives you sketched out above?

When a priv is dropped it stays dropped until it's reinstated. If
code drops a priv that it can't re-enable then the priv is gone.
(There are going to be issues with privileges attached to
continuations, since this could potentially mean that dropped privs
get un-dropped when you invoke a return continuation, though dropping
a privilege could ripple up the return continuation chain)

> > Additionally, subroutines may be marked as having privileges, which
>> means that as long as control is inside the sub the priv in question
>> is enabled. This allows for code that has elevated privs, generally
>> system-level code.
>
>Does the code marking a subroutines must have any other privilege than
>the one it is marking the subroutine with?

Dunno, that's something we'll need to work out. It's possible that
sub marking needs to be done externally -- that is, it's bytecode
metadata or something like that which requires system privileges of
some sort to set. (Though there are issues with that) Marking code as
privileged is really a system administration task, though we've not
really put much thought into administering a parrot system yet.

> > ... Non-continuation
>> invokables (subs and methods) maintain the current set of privs, plus
>> possibly adding the sub-specific privs.
>
>Same for closures?

Yeah, I think so.

Aaron Sherman

unread,
Apr 14, 2005, 10:44:46 AM4/14/05
to Dan Sugalski, Perl6 Internals List
On Thu, 2005-04-14 at 09:11, Dan Sugalski wrote:
> At 10:03 PM -0400 4/13/05, Michael Walter wrote:

> >On 4/13/05, Dan Sugalski <d...@sidhe.org> wrote:
> >> All security is done on a per-interpreter basis. (really on a
> >> per-thread basis, but since we're one-thread per interpreter it's
> >> essentially the same thing)

> >Just to get me back on track: Does this mean that when you spawn a
> >thread, a separate interpreter runs in/manages that thread, or
> >something else?
>
> We'd decided that each thread has its own interpreter. Parrot doesn't
> get any lighter-weight than an interpreter, since trying to have
> multiple threads of control share an interpreter seems to be a good
> way to die a horrible death.

So to follow up on Michael's question: does this mean that you spawn a
new thread, instance an interpreter, and then begin executing shared
code? What about data? I assume that all has to be shared, since shared
data is a fundamental piece of any threaded application's assumptions.

Dan Sugalski

unread,
Apr 14, 2005, 10:48:22 AM4/14/05
to Aaron Sherman, Perl6 Internals List
At 10:44 AM -0400 4/14/05, Aaron Sherman wrote:
>On Thu, 2005-04-14 at 09:11, Dan Sugalski wrote:
>> At 10:03 PM -0400 4/13/05, Michael Walter wrote:
>
>> >On 4/13/05, Dan Sugalski <d...@sidhe.org> wrote:
>> >> All security is done on a per-interpreter basis. (really on a
>> >> per-thread basis, but since we're one-thread per interpreter it's
>> >> essentially the same thing)
>
>> >Just to get me back on track: Does this mean that when you spawn a
>> >thread, a separate interpreter runs in/manages that thread, or
>> >something else?
>>
>> We'd decided that each thread has its own interpreter. Parrot doesn't
>> get any lighter-weight than an interpreter, since trying to have
>> multiple threads of control share an interpreter seems to be a good
>> way to die a horrible death.
>
>So to follow up on Michael's question: does this mean that you spawn a
>new thread, instance an interpreter, and then begin executing shared
>code?

Yes.

> What about data?

Data needs to be explicitly shared.

Dave Whipp

unread,
Apr 14, 2005, 12:51:26 PM4/14/05
to perl6-i...@perl.org
Dan Sugalski wrote:

> All security is done on a per-interpreter basis. (really on a per-thread
> basis, but since we're one-thread per interpreter it's essentially the
> same thing)

...


> * Number of open files
> * IO operations/sec
> * IO operations total

...

Can an "application" get more resources simply by spawning threads? If
the answer is "no, parent and child must divide share their quotas" then
there is a load balancing problem. If the answer is "yes", then there's
no real protection at all. A threads-per-second limit isn't an answer
here, either (a malicious app could sit around for a few hours,
launching threads at a low intensity, until it has enough to bring down
the system).

Is a thread really the right thing to apply these limits to? It seems to
me that there needs to be some sort of token (cf. cash; cf "capability")
that an application can obtain/spend/refresh to do these ops. An
application could share its token(s) with any threads it creates. It
could probably even "loan" its token to a backgroud thread that does
some operation on behalf of many other threads.

Dan Sugalski

unread,
Apr 14, 2005, 1:22:11 PM4/14/05
to Aaron Sherman, Perl6 Internals List
At 5:51 PM -0400 4/13/05, Aaron Sherman wrote:
>On Wed, 2005-04-13 at 17:01, Dan Sugalski wrote:
>> So here's what I was thinking of for Parrot's security and quota
>> model. (Note that none of this is actually *implemented* yet...)
>[...]
>> It's actually pretty straightforward, the hard part being the whole
>> "don't screw up when implementing" thing, along with designing the
>> base set of privs. Personally I think taking the VMS priv and quota
>> system as a base is a good way to go -- it's well-respected and
>> well-tested, and so far as I know theoretically sound. Unix's priv
>> model's a lot more primitive, and I don't think it's the one to take.
>> (We could invent our own, but history shows that people who invent
>> their own security system invent ones that suck, so that looks like
>> something worth avoiding)
>
>VMS at least *is* a priv-based security model, but VMS privs are not
>appropriate for parrot on the whole.

Right. The privileges themselves are generally inappropriate for our
use, which is fine. It's the model that I'm interested in, as it's
the model that gets screwed up so badly, or so I'm told.

Anyway, a number of people I deeply respect (and who do this sort of
thing for a living, at deep levels) have told me flat-out that we're
better not having a security system than we are trying to roll our
own, and the common response to "We're lifting VMS'" has been "Good.
Do that."

>I think it would be easier to start from scratch, personally. I
>understand your concerns, but I don't think you run any less risk by
>creating a new VM security model out of an OS security model than you do
>by creating a new one. They both create many opportunities to make a
>mistake.

That's not been the general consensus I've seen from people doing
security research and implementation. This is an area that I've no
real experience doing any sort of design in, and the people who have
the experience say not to, so I think it best to take them at their
word.

>If you really want to reduce the chances that you'll make a mistake,
>swipe the security model from JVM or CLR and start with that. At least
>those have been tested in the large, and map closer to what Parrot wants
>to do than VMS.

The problem is twofold with those. First, there's some indications
that they're busted, and second (and more importantly) they're both
very coarse-grained, and that leads to excessive privs being handed
out, which increases your exposure to damage. If a library routine
needs to potentially exceed memory quotas we'd rather not give it the
equivalent of root privileges.

>Don't get me wrong. I loved VMS back in the day. It was a pain in the
>ass at times, but what isn't. It's just that it's not a VM trying to
>execute byte-code... it's an operating system which directly manages
>hardware.

Yeah, but don't forget that for all intents and purposes parrot is an
OS trying to execute bytecode, especially when you look at the
environments that the features will get used in.

Dan Sugalski

unread,
Apr 14, 2005, 1:29:04 PM4/14/05
to perl6-i...@perl.org
At 9:51 AM -0700 4/14/05, Dave Whipp wrote:
>Dan Sugalski wrote:
>
>>All security is done on a per-interpreter basis. (really on a
>>per-thread basis, but since we're one-thread per interpreter it's
>>essentially the same thing)
>...
>> * Number of open files
>> * IO operations/sec
>> * IO operations total
>...
>
>Can an "application" get more resources simply by spawning threads?
>If the answer is "no, parent and child must divide share their
>quotas" then there is a load balancing problem. If the answer is
>"yes", then there's no real protection at all. A threads-per-second
>limit isn't an answer here, either (a malicious app could sit around
>for a few hours, launching threads at a low intensity, until it has
>enough to bring down the system).

Spawning threads may require a privilege, and there should be a quota
for it, so the number of spawned threads could be managed.

I can see sharing quotas across multiple threads, though there are
issues there (like sharing CPU time) as well.

>Is a thread really the right thing to apply these limits to? It
>seems to me that there needs to be some sort of token (cf. cash; cf
>"capability") that an application can obtain/spend/refresh to do
>these ops. An application could share its token(s) with any threads
>it creates. It could probably even "loan" its token to a backgroud
>thread that does some operation on behalf of many other threads.

Well, and interpreter is as fine-grained as we can get, and you're
right, we may want to get a bit broader and share quotas amongst
multiple threads. I don't know that we want to get much fancier than
grouping threads together, though -- while I can see it being useful
in a few cases, I'm not sure in practice that anyone'd actually want
to do that.

Aaron Sherman

unread,
Apr 14, 2005, 11:27:24 PM4/14/05
to Dan Sugalski, Perl6 Internals List
On Thu, 2005-04-14 at 13:22 -0400, Dan Sugalski wrote:

> Anyway, a number of people I deeply respect (and who do this sort of
> thing for a living, at deep levels) have told me flat-out that we're
> better not having a security system than we are trying to roll our
> own, and the common response to "We're lifting VMS'" has been "Good.
> Do that."

Well, if you were lifting VMS's security model, that would be fine, but
you're really not. You're lifting the idea of VMS's security model.

A security model is a many-fold thing (I've only so far discussed the
highest and most user-visible level because they are the bits most
applicable to Parrot). You're talking about cherry-picking certain bits
and re-designing the rest to fit.

I have NO PROBLEM with that, but I want to make sure that you don't
think this is the easy way to go. It's not. You're biting off a HUGE
amount of work, and your first 2 attempts will likely be utterly wrong
(if history is any guide, not because you're not smart and capable).

> >I think it would be easier to start from scratch, personally. I
> >understand your concerns, but I don't think you run any less risk by
> >creating a new VM security model out of an OS security model than you do
> >by creating a new one. They both create many opportunities to make a
> >mistake.
>
> That's not been the general consensus I've seen from people doing
> security research and implementation.

They both create many opportunities to make a mistake. Really. Go ask
the folks at Microsoft who "lifted VMS" for NT's security model, and
then go ask the folks at Sun who rolled their own with Java. Both have
had significant pain.

> >If you really want to reduce the chances that you'll make a mistake,
> >swipe the security model from JVM or CLR and start with that. At least
> >those have been tested in the large, and map closer to what Parrot wants
> >to do than VMS.
>
> The problem is twofold with those. First, there's some indications
> that they're busted,

They're not "busted" so much as in many places they have needed
significant work. I think that the general consensus right now is that
JVM is fairly well sorted out in 1.5, and CLR is moving along well.

I would say that at an infrastructure level they're both more than
sufficient models, and that's all you're going to lift anyway (unless
you were considering lifting code from mono, which I'm not sure is
workable license-wise).

> and second (and more importantly) they're both
> very coarse-grained, and that leads to excessive privs being handed
> out, which increases your exposure to damage.

That's fine. Merging down either JVM or CLR's privs into a granularity
that you're happy with should work fine, and again, privs are only a
small part of the security model. If you want a better picture these
sources might be useful:

http://developer.intel.com/technology/itj/2003/volume07issue01/art05_security/vol7iss1_art05.pdf
http://java.sun.com/docs/books/security/
http://www.arctecgroup.net/ISB0705GP.pdf
http://www.arctecgroup.net/ISB0706GP.pdf
http://www.arctecgroup.net/ISB0707GP.pdf

> >Don't get me wrong. I loved VMS back in the day. It was a pain in the
> >ass at times, but what isn't. It's just that it's not a VM trying to
> >execute byte-code... it's an operating system which directly manages
> >hardware.
>
> Yeah, but don't forget that for all intents and purposes parrot is an
> OS trying to execute bytecode,

VMS security was interesting because it was one of the first systems to
substantially abstract the security of the system from the security of
the hardware. You don't get to touch hardware because you're user-land,
so you have a very different set of concerns. You do, however, have
roughly the same set of concerns as the JVM and CLR. That's why I
suggested them. If you don't like them, that's cool, I was only trying
to save those of you who have enough time to think about something as
large as security infrastructure some time and pain.

I don't have that kind of spare time, so I bow to your superior ability
to manage your schedule.


Shevek

unread,
Apr 15, 2005, 5:59:23 AM4/15/05
to Perl6 Internals
On Thu, 2005-04-14 at 09:51 -0700, Dave Whipp wrote:
> Dan Sugalski wrote:
>
> > All security is done on a per-interpreter basis. (really on a per-thread
> > basis, but since we're one-thread per interpreter it's essentially the
> > same thing)
> ...
> > * Number of open files
> > * IO operations/sec
> > * IO operations total
> ...
>
> Can an "application" get more resources simply by spawning threads? If

Well, given that a child thread's dynamic access control context should
include the dynamic context of the parent thread at the point where the
thread was spawned, No.

What I describe is a (provably) correct implementation.

> the answer is "no, parent and child must divide share their quotas" then
> there is a load balancing problem. If the answer is "yes", then there's

There is no load balancing problem assuming you are synchronized on the
thread-create point, which is not a major overhead, since that pretty
much has to be a synchronization point in the kernel anyway.

> no real protection at all. A threads-per-second limit isn't an answer
> here, either (a malicious app could sit around for a few hours,
> launching threads at a low intensity, until it has enough to bring down
> the system).
>
> Is a thread really the right thing to apply these limits to? It seems to

Limits are applied to privilege sets, not to threads.

> me that there needs to be some sort of token (cf. cash; cf "capability")
> that an application can obtain/spend/refresh to do these ops. An

Yes, that's about the same.

> application could share its token(s) with any threads it creates. It
> could probably even "loan" its token to a backgroud thread that does
> some operation on behalf of many other threads.

Preferably not. I fear the concept of being able to hand out privileges
to low privilege threads. If the low privilege thread has access to a
(willing) object with static privileges allowing the operation, then
that object should perform the operation on behalf of the thread in a
dynamic context created by a 'grant' operation (See Fournet and Gordon,
2003). If the low privilege thread is made up entirely of low privilege
objects, then it shouldn't have the privilege under any circumstances.

S.


Shevek

unread,
Apr 15, 2005, 5:56:20 AM4/15/05
to Perl6 Internals
On Wed, 2005-04-13 at 17:51 -0400, Aaron Sherman wrote:
> On Wed, 2005-04-13 at 17:01, Dan Sugalski wrote:
> > So here's what I was thinking of for Parrot's security and quota
> > model. (Note that none of this is actually *implemented* yet...)
> [...]
> > It's actually pretty straightforward, the hard part being the whole
> > "don't screw up when implementing" thing, along with designing the
> > base set of privs. Personally I think taking the VMS priv and quota
> > system as a base is a good way to go -- it's well-respected and
> > well-tested, and so far as I know theoretically sound. Unix's priv
> > model's a lot more primitive, and I don't think it's the one to take.
> > (We could invent our own, but history shows that people who invent
> > their own security system invent ones that suck, so that looks like
> > something worth avoiding)
>
> VMS at least *is* a priv-based security model, but VMS privs are not
> appropriate for parrot on the whole.

The best known model for privileges (logic of authorisation over) is
that of Oracle, RT, etc, where access over privileges is transitive.
Will find good references on request/when I have more time. Bad
references are available from Ravi Sandhu, but he doesn't handle
transitivity or modification of rights well, if at all.

S.


Shevek

unread,
Apr 15, 2005, 5:54:08 AM4/15/05
to Perl6 Internals
Someone's pointed this thread out to me, so I'm going to shove an oar in
following a few posts. I've done a fair bit of security work, so feel
free to ask me to explain, justify or provide references for anything.

On Wed, 2005-04-13 at 17:01 -0400, Dan Sugalski wrote:
> All security is done on a per-interpreter basis. (really on a
> per-thread basis, but since we're one-thread per interpreter it's
> essentially the same thing)

What you actually mean (or what I believe you _should_ mean) is
per-context, in the lambda-calculus sense of context. See notes below
about continuations.

> QUOTAs are limits on the number of resources or operations that an
> interpreter an allocate or perform, either in absolute terms (i.e.
> allocate no more than 10M of memory) or relative terms (i.e. can do
> only 10 IO operations per second). Quotas are tracked by parrot, and
> cover:

The ability to manipulate and exceed QUOTAs should be controlled in
dynamic context.

> PRIVILEGEs are permissions to do certain things. Parrot will have a
> number of privileges it checks before doing dangerous operations, and
> user code may also assign and check privileges.
>
> Normally parrot runs with no quotas and no privilege checking. This
> is the fastest way to run. Code may at any time enable privilege

Actually, you can do privilege checking in an efficient engine, even
using most of the reflection systems, with almost no overhead. See Java.

> and/or quota checking. Once enabled code must have proper privileges
> to disable it again.

Typically AllPermission, otherwise you have the ability to perform
privilege escalation.

> Each running thread has two sets of privileges -- the active
> privileges and the enableable privileges. Active privs are what's
> actually in force at the moment, and can be dropped at any time. The
> enableable privs are ones that code can turn on. It's possible to
> have an active priv that's not in the enableable set, in which case
> the current running code is allowed to do something but as soon as
> the privilege is dropped it can't be re-enabled.

Enableable privileges are usually called static privileges and are
usually defined as the privileges held statically by the current object,
or if we read ahead to your next point, subroutine.

> Additionally, subroutines may be marked as having privileges, which
> means that as long as control is inside the sub the priv in question
> is enabled. This allows for code that has elevated privs, generally
> system-level code.

Please no. Privileges should be explicitly granted. You have just
described the Unix SUID model, where as long as control is inside a
root-owned daemon (for daemon, read subroutine), the root privilege is
enabled. This always leads to privilege escalation and is BAD.

What you _should_ mean, according to all prior research, is that "No
code may be inside that routine and still hold a privilege not held by
the routine". In shorter form, "The dynamic (current) privilege set must
not exceed the static privilege set of any routine on the stack". A
slightly different formulation applies for data inspection systems. See
footnote.

> Continuations, when taken, capture the current set of active and
> enableable privs, and when invoked those privs are put into place.
> (This is a spot that will require some thought, since there's a
> potential for privilege leaks which worries me here) Non-continuation
> invokables (subs and methods) maintain the current set of privs, plus
> possibly adding the sub-specific privs.

If you perform the above step correctly, then capturing a context and
including it in future access control checks is not hard. Java does this
by capturing a current AccessControlContext when a new ClassLoader is
created in a thread to be used in a different thread. No code loaded by
that ClassLoader IN ANY THREAD may exceed the privileges of the thread
which created the classloader at the time it created it.

> It's actually pretty straightforward, the hard part being the whole
> "don't screw up when implementing" thing, along with designing the
> base set of privs. Personally I think taking the VMS priv and quota
> system as a base is a good way to go -- it's well-respected and
> well-tested, and so far as I know theoretically sound. Unix's priv
> model's a lot more primitive, and I don't think it's the one to take.
> (We could invent our own, but history shows that people who invent
> their own security system invent ones that suck, so that looks like
> something worth avoiding)

Better systems to inspect would be Java (stack inspection), Perl5 (data
inspection). Please do not confuse the choice of privilege set and logic
over it (authorisation system) with the mechanism for identifying the
current set of privileges (identification of current principal).

The key difference in security between stack inspection and data
inspection systems for the purposes of parrot is that stack inspection
considers for security purposes the dynamic context of the thread, but
permits untrusted returned values to participate in computation, while
data inspection does not permit this, but allows the evaluation of a
closed (in the lambda-sense) expression in an untrusted dynamic context.

S.


Shevek

unread,
Apr 15, 2005, 6:03:11 AM4/15/05
to Perl6 Internals
On Wed, 2005-04-13 at 22:03 -0400, Michael Walter wrote:
> Dan,
>
> On 4/13/05, Dan Sugalski <d...@sidhe.org> wrote:
> > All security is done on a per-interpreter basis. (really on a
> > per-thread basis, but since we're one-thread per interpreter it's
> > essentially the same thing)
> Just to get me back on track: Does this mean that when you spawn a
> thread, a separate interpreter runs in/manages that thread, or
> something else?
>
> > Each running thread has two sets of privileges -- the active
> > privileges and the enableable privileges. Active privs are what's
> > actually in force at the moment, and can be dropped at any time. The
> > enableable privs are ones that code can turn on. It's possible to
> > have an active priv that's not in the enableable set, in which case
> > the current running code is allowed to do something but as soon as
> > the privilege is dropped it can't be re-enabled.
>
> How can dropping a privilege for the duration of a (dynamic) scope be
> implemented? Does this need to be implemented via a parrot intrinsic,
> such as:
>
> without_privs(list_of_privs, code_to_be_run_without_these_privs);
>
> ..or is it possible to do so with the primitives you sketched out above?

This is usually done by creating a function "f(code) { code() }" without
any static privileges in list_of_privs. To evaluate a function g()
without those privileges, evaluate f(g), and the natural mechanisms of
the interpreter will ensure that these privileges are not held during
g().

> > Additionally, subroutines may be marked as having privileges, which
> > means that as long as control is inside the sub the priv in question
> > is enabled. This allows for code that has elevated privs, generally
> > system-level code.
>
> Does the code marking a subroutines must have any other privilege than
> the one it is marking the subroutine with?
>
> > ... Non-continuation
> > invokables (subs and methods) maintain the current set of privs, plus
> > possibly adding the sub-specific privs.
>
> Same for closures?

Closures may also capture a concept of the current context, which is
used when they are evaluated. This is critical in, for example, the case
of system code with higher static privileges returning a closure to a
low privilege object which may evaluate it at any time.

a) The closure must not have any privileges not held by the low
privilege object, so clearly it cannot just hold its static privilege
set, it must capture a current context.

b) If it does wish to have higher privilege (very common), it may grant
(Fournet+Gordon,2003) these privileges in a dynamic scope bounded below
by itself.

S.


Shevek

unread,
Apr 15, 2005, 6:09:05 AM4/15/05
to Perl6 Internals
On Thu, 2005-04-14 at 09:11 -0400, Dan Sugalski wrote:
> At 10:03 PM -0400 4/13/05, Michael Walter wrote:

> > > Each running thread has two sets of privileges -- the active
> >> privileges and the enableable privileges. Active privs are what's
> >> actually in force at the moment, and can be dropped at any time. The
> >> enableable privs are ones that code can turn on. It's possible to
> >> have an active priv that's not in the enableable set, in which case
> >> the current running code is allowed to do something but as soon as
> >> the privilege is dropped it can't be re-enabled.
> >
> >How can dropping a privilege for the duration of a (dynamic) scope be
> >implemented? Does this need to be implemented via a parrot intrinsic,
> >such as:
> >
> > without_privs(list_of_privs, code_to_be_run_without_these_privs);
> >
> >..or is it possible to do so with the primitives you sketched out above?
>
> When a priv is dropped it stays dropped until it's reinstated. If
> code drops a priv that it can't re-enable then the priv is gone.
> (There are going to be issues with privileges attached to
> continuations, since this could potentially mean that dropped privs
> get un-dropped when you invoke a return continuation, though dropping
> a privilege could ripple up the return continuation chain)

Reinstating privileges when you return is normal, since potentially
malicious code and data has now been removed from the stack.

If you do NOT do it this way, then every piece of code must know the
privileges of every child piece of code it calls (bye-bye virtual base
classes with user implementations).

See http://research.microsoft.com/~adg/Publications/MSR-TR-2001-103.pdf

The ability to explicitly reenable a privilege via an opcode, rather
than via the removal of the malicious party from the computation (by
return) is almost definitely a bad idea. If you protect this opcode
using some security mechanism, you will rapidly find that security
mechanism can supersede the functionality provided by the opcode.

> > > Additionally, subroutines may be marked as having privileges, which
> >> means that as long as control is inside the sub the priv in question
> >> is enabled. This allows for code that has elevated privs, generally
> >> system-level code.
> >
> >Does the code marking a subroutines must have any other privilege than
> >the one it is marking the subroutine with?
>
> Dunno, that's something we'll need to work out. It's possible that
> sub marking needs to be done externally -- that is, it's bytecode
> metadata or something like that which requires system privileges of
> some sort to set. (Though there are issues with that) Marking code as
> privileged is really a system administration task, though we've not
> really put much thought into administering a parrot system yet.

Actually, what usually happens is that subroutines (etc) are associated
with a responsible party (principal), and privileges are granted to the
principal; thus finding out the privileges of an opcode requires an
extra indirection. This is not a problem.

> > > ... Non-continuation
> >> invokables (subs and methods) maintain the current set of privs, plus
> >> possibly adding the sub-specific privs.
> >Same for closures?
>
> Yeah, I think so.

No, as before. You cannot execute based only on static privileges - this
is what Unix does, and the Unix model is broken. You need either a stack
inspection or a data inspection model, or a combination of the two. Ask
me if you want formal descriptions or implementation details of these
models.

S.


Michael Walter

unread,
Apr 16, 2005, 2:41:24 AM4/16/05
to Shevek, Perl6 Internals
On 4/15/05, Shevek <pe...@anarres.org> wrote:
> > How can dropping a privilege for the duration of a (dynamic) scope be
> > implemented? Does this need to be implemented via a parrot intrinsic,
> > such as:
> >
> > without_privs(list_of_privs, code_to_be_run_without_these_privs);
> >
> > ..or is it possible to do so with the primitives you sketched out above?
>
> This is usually done by creating a function "f(code) { code() }" without
> any static privileges in list_of_privs.
>
> To evaluate a function g()
> without those privileges, evaluate f(g), and the natural mechanisms of
> the interpreter will ensure that these privileges are not held during
> g().

I understand, thanks.
Michael

Reply all
Reply to author
Forward
0 new messages