Access to resources in SecureSqueak is controlled using Dominions (also previously called Domains, Realms or ResourceDomains). This is a way of controlling resource usage in an image. For example, it would control excessive memory usage, excessive forking of Processes, using too much disk space, etc.
Each Dominion is allocated certain levels of resources depending on the user's preferences. Resources include:
Every object in an image belongs to one Dominion. When a resource is used, the Dominion of the object using that resource is "billed". When an object tries to use a resource but the dominion of that object has used up its resource allowances, a (recoverable) exception is thrown.
For example, say that a SiteBrowser is an application that visits Sites which are implemented by code loaded from across a network. Each Site has an associated Dominion. When a Site object has been instantiated, new resources are granted to that Site's dominion (for example, CPU priority capped at 35, no more than 10MB disk, no more than 20MB/s over the network, access only to sound and a Canvas). When the SiteBrowser leaves that Site and goes to another, those resources will be denied to the previously visited Site's dominion. In this way, it is impossible for a particular Site to exceed its resource usage and cause a denial of service to other objects in an image.
Dominions could perhaps contain a dictionary of capabilities, such as capabilities that allow that object to make a class or introspect other objects.
The information about which Dominions can access how much of each resource is stored externally to the Dominions, perhaps by a DominionManager?
In a distributed system involving multiple running images communicating over a network, a "Dominion" could span multiple machines. In this case, distributed services could also use the dominion mechanism to find resources such as an idle CPU or disk space.
Dominions can be used for stating the requirements of code: this code requires at least 200MIPS CPU, 20MB object space and 10MB/s network or it won't run well. This will allow the computer to state that it cannot meet the requirements of all the dominions it is hosting.
Dominions form a mechanism of controlling and accounting resources on remote machines. This allows hosting providers (ISPs etc) to account and charge for services provided.
A Dominion is an Object.
Every object in an image belongs to one Dominion. The reason for this rather than making a Package belong to a dominion (in the same manner that Java applies security permissions to jar files) is because multiple groups of objects might have different security requirements but share the same code. For example, an image might have several objects of class Document, but each Document instance would be in its own Dominion so that one particular Document doesn't consume all the resources for every Document in the image.
Making every object belong to a Dominion can be implemented in multiple ways:
The active dominion will need to be accessed when:
Access to resources would be monitored when that resource is used. The call stack can be traced back until a suitable dominion is found. The call stack would comprise of instance methods, class methods and blocks. The dominion of an instance method is the dominion of the object that method is on.
The dominion of a class method would be a system dominion and would mean that the call stack would need to be traced back further.
The dominion of a block is the dominion of the object that invoked that block.
The dominion of a Process continually changes depending on the currently executed context.
SmallIntegers have no dominion; the call stack will need to be traced further back.
Memory usage can be controlled by modifying ProtoObject>>basicNew(...) to first check if the given dominion is still permitted to create new objects.
There doesn't need to be a limit on the size of a call stack or number of forked processes. Provided that the scheduler bases the amount of CPU time a dominion gets fairly (and not in proportion to the number of threads that dominion has forked), a dominion is only constrained by its memory limits when forking new processes or invoking recursive methods.
The implementation of the Squeak scheduler could be modified to give fair CPU access across all dominions. A limit on the highest priority available to a dominion can be enforced.
A limit on the number of forked processes could be put into place to simulate the use of a set of worker threads. When that limit has been reached, the next "[...] fork" will block until another process in that dominion has terminated. This could unfortunately be a source of bugs; if code requires a certain number of processes to work but it cannot create that many processes, that program may fail. A better solution would be to implement the scheduler to favour executing child threads to completion rather than creating new processes.
When a dominion is revoked, the dominion could have some event or callback mechanism to have that dominion's object tidy up after themselves. After that, the dominion can be forcefully removed and references to any object in that dominion nullified.
When a dominion reaches one or another limit, an exception will need to be thrown from... somewhere? If the dominion can't handle the situation (by decreasing resource usage) then the user will need to be notified.
Maximum values are specified to control resource usage.
Minimum values are used to decide whether the hosting machine has enough spare capacity to host this dominion. A particular machine cannot allocate more than 100% of its resources.
CPU usage is either batch or real-time. Batch tasks don't mind being denied CPU for a few seconds or minutes. Real-time tasks do.
CPU can be allocated using:
A service that is being hosted on a particular CPU would have real-time and batch CPU requirements. The real-time component provides a minimum level of service even if the machine is under high load; the batch component will allow idle resources on that machine to be utilised.
Currently in Squeak, CPU priority is an all-or-nothing affair. The highest priority task gets all CPU.
The scheduler could be, for development's sake, implemented as a Squeak object. An object with at least a single variable which would store the next process to run. That object would have a particular method activated by the VM when scheduling is needed, and that object would set that variable to the next process that would need to be run. When done, the object would call a primitive method or something where the VM would pick up the value of that variable and use it as the next process to run.
Then, the scheduler would need to be activated on a regular basis. Perhaps the VM could have its own interrupt or something every n milliseconds?
Network usage is like CPU usage but more complicated. More thought needed here.
Memory can be allocated by specifying the maximum size and minimum size requirements needed to run.
Types of memory include normal and cache. "Cache" memory is memory that can be discarded if resources are low; a memory manager of some sort would look at the "cache" memory usage values for each dominion and make decisions as to which dominions are asked to discard cache.
A service would usually specify a minimum memory requirement; if the local machine cannot supply that much memory then that service will not be able to be run.
The maximum requirements don't always need to be specified; these exist primarily to avoid run-away resource usage as a result of memory leaks, and for accounting purposes so that memory hogs can be terminated to free up memory.
Disk can be allocated by specifying the maximum size and minimum size requirements needed to run. This is similar to memory.
All these resources need to be shared evenly between all hosted dominions based on priorities.
When a resource is nearing saturation (e.g. at 80%?), that dominion will be sent a notification that gives it an opportunity to reduce resource usage. This also applies when resource allocations are modified - say for example that memory is reduced from 20MB to 10MB for a particular dominion; the resource is first notified; the notification thread is given some time to complete and then the resource allowance for that dominion is reduced.
If Object>>dominion returns that object's dominion, then any class could access that dominion and make objects in that dominion. This allows for resource theft. This means that Object>>dominion cannot return a dominion that allows for resource usage in the returned dominion.
So how do you allow only the DominionManager to work out which object is in which dominion?
More generally, how do you make sure that a method can only return a confidential result to one object?
private methods:
thisContext sender receiver = self ifFalse: [^ SecurityException signal]
or
thisContext sender receiver class = DominionManager ifFalse: [^ SecurityException signal].
or
(Sender is: self) ifTrue: [...]
(where Sender is a global variable that doesn't let you get the actual reference.)
Access to an object's dominion by another object not in that dominion allows resource theft.
APIs available to objects outside the current dominion may allow for a memory leak. This can happen by, for example, objects in one dominion holding on to objects in another dominion thus preventing them from being GCed.
A block might allow for resource theft, particularly if that block contains references.
A Dominion object could also be used to store shared variables. For example, the owner of that dominion could be a user that would need to be notified - that user's UI would be a shared variable.
References to a Dominion object grant the holder to use resources in that dominion.
...thought: unless resource access to a dominion is granted by looking at the object's actual reference, by introspection, and then preventing that object from being able to modify its own dominion reference??
...thought: perhaps a dominion reference does not grant the holder to use resources?
The user would occasionally need to track down which dominions are using resources on his computer.
An audit of the entire image would need to be performed, perhaps using the garbage collector. This audit would involve querying every single object in the image about which dominion it belongs to. A list or tree of all dominions would be returned for the user to maintain.
Operations which could be invoked on a Dominion could be:
Generally, dominion management should be automated as far as possible. If a user decides to run a particular service, he will need to allocate resources to that dominion. If a browser-style UI is used, the dominion of whatever site is currently being visited can be allocated resources automatically and have those resources revoked when the user leaves that page (although some caching mechanism would be needed). Management would probably be done by parent dominions of the dominion which is being managed, and failing that then by the user.
What happens when the dominion's resources are exhausted?
What happens when the dominion resources are reduced to below the limits set?
What happens when a dominion is forcefully removed?
One dominion could be a child of another. A child dominion would need to share resources with it's parent. This may ease administration of dominions.
A firewall could be implemented to disallow objects of private dominions to pass through it.
Multiple computers in a distributed system could share a dominion between themselves. Several computers could allocate resources to a particular dominion such that that dominion spans a cluster of computers.
[...] doRemotely. "Execute that block on any server in the current dominion."
aDominion storageService storeAnywhere: aByteArray id: anID redundancy: n. "Store that byte array into storage."
A dominion manage could be made which lets the user view/edit the total resources a dominion currently occupies, how much it has available, and the servers that a dominion has available to it.
User-visible objects could be browsed in a hierarchy of dominions. Each user-visible object ("documents") would be a dominion in it's own right. Each dominion would have a "main object" which would be an object that returns an icon, responds to the "open" command etc. This object can be nil, in which case the dominion is just a dominion.
SiteBrowser would allow the currently browsed Site particular resources locally. When the site is navigated away from (the site is passified), the resources it is granted are reduced to background status. Background processes must not spoil interactivity.The user should be able to choose how many resources a particular site is granted locally.
The user would be able to grant particular dominions resources on the local host.
A local network (or current ISP hosted) "accelerater" machine could provide resources for domains that users are using - i.e. the SiteBrowser would know that an accelerater machine is nearby and get that machine to grant resources to currently viewed dominions. In effect, the accelerator machine becomes part of the distributed network hosting objects that appear on Sites, depending on demand.
A user would be able to purchase hosting on one or more remote hosting services, and then assign those resources to particular dominions.
This example assumes that Dominions have been implemented by demarcating the stack frames. Every stack frame has a "dominion" variable in it, and the dominion is inherited from that frame's parent.
SiteBrowser would visit Sites. Each Site is a distributed object. Each Site would have an existing dominion that is assigned to it at creation; the dominion would be stored as an instance variable.
When a Site is interacted with, the following could happen:
These are the basic requirements for dominion-based management:
When a site is activated:
SiteBrowser>>activateSite: aSite
| d |
d := aSite dominion. " Security alert: what happens if >>dominion is overridden? How about:"
" d := Dominion of: aSite "
dominions at: aSite put: d.
self grantResourcesTo: d.
It should not matter if an object overrides >>dominion; that object should not have access to other dominions.
When a site is deactivated:
SiteBrowser>>deactivateSite: aSite
self retractResourcesFrom: (dominions at: aSite). " Security problem: what if the site lies about its dominion? "
It might be necessary to keep track of which Site has which dominion.
Every invocation on the Site then needs to be put in a particular dominion. This could be done by every calling method:
SiteBrowser>>draw
self enterDominion: (self dominionForSite: currentSite).
[currentSite drawOn: screen] fork.
Alternatively:
SiteBrowser>>draw
[currentSite drawOn: screen] forkInDominion: (self dominionForSite: currentSite).
A dominion can only be exited when a stack frame returns.
However, this leave the problem of accidently invoking a method on aSite without first entering aSite's dominion. We could consider any such invocation to be a security risk. Alternatively, we could always run in a dominion with very limited privileges, and the Site receives more privileges than the calling thread. The latter is problematic:
SiteBrowser should receive more CPU time than its Sites, but does not need as much memory or extra resources.
Alternatively, a Site might have all methods invoked on a minimally enabled dominion, and it is the responsibility of the Site to hold a reference to its own dominion and to enter it.
What does the scheduler do when it reschedules? A call stack could consist of many dominions; each element of the call stack is an object that is consuming memory and that consumed memory needs to be added and removed from that dominion.
Invocation of class-side methods and primitives should be transparent to dominions; the dominion that is billed for its resource usage is found by iterating down through the stack until a dominioned object is found.
Page Information
|
Wiki Information |
Recent PBwiki Blog Posts |