Re: A sketch of the security model
On 4/15/05, Shevek [EMAIL PROTECTED] 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
Re: A sketch of the security model
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
Re: A sketch of the security model
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.
Re: A sketch of the security model
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.
Re: A sketch of the security model
On Wed, 2005-04-13 at 22:03 -0400, Michael Walter wrote: Dan, On 4/13/05, Dan Sugalski [EMAIL PROTECTED] 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.
Re: A sketch of the security model
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.
Re: A sketch of the security model
At 10:03 PM -0400 4/13/05, Michael Walter wrote: Dan, On 4/13/05, Dan Sugalski [EMAIL PROTECTED] 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. -- Dan --it's like this--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: A sketch of the security model
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 [EMAIL PROTECTED] 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. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: A sketch of the security model
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 [EMAIL PROTECTED] 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. -- Dan --it's like this--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: A sketch of the security model
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.
Re: A sketch of the security model
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 --it's like this--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: A sketch of the security model
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. -- Dan --it's like this--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: A sketch of the security model
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.
A sketch of the security model
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 [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: A sketch of the security model
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. DETACHCreate detached processes. EXQUOTA Exceed resource quotas. SETPRVGrant a process any privilege. SHMEM Create or delete data structures in shared memory. SYSGBLCreate system global sections. SYSLCKRequest 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. BUGCHKMake bugcheck error log entries. CMEXECChange mode to Executive. CMKRNLChange mode to Kernel. DIAGNOSE Issue diagnostic I/O requests. GRPNAMEnter names in the group logical name table. GRPPRVAllow access to files in the group and system categories. MOUNT Issue mount volume I/O requests. PHY_IOIssue physical I/O requests. PRMCEBCreate permanent common event flag clusters. PRMGBLCreate permanent global clusters. PSWAPMChange process swap mode. SHARE Assign a channel to a device. SYSNAMEnter names in the system logical name table. TMPMBXCreate temporary mailbox devices. VOLPROOverride 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 ALTPRIIncrease the base execution priority for any process. change to: Allow QUOTA modification BYPASSAccess 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_IOIssue logical I/O requests. if we assume that this means any handle I/O NETMBXCreate 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 PFNMAPCreate or delete sections mapped by page frame. Allocate new PMCs PRMMBXCreate permanent mailbox devices. Create special files of any sort (e.g. POSIX fifo) SECURITY Perform security-related functions. ? SYSPRVAccess 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
Re: A sketch of the security model
Dan, On 4/13/05, Dan Sugalski [EMAIL PROTECTED] 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