Dominions

 

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:

  • CPU usage (i.e. maximum process priority).
  • Memory usage (number of objects made).
  • Network bandwidth.
  • Disk usage.
  • Device usage.
  • Access to capabilities.

 

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.

 

Implementation

 

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:

 

  • In the current prototype, a complicated manner of copying classes and metaclasses is used, and the metaclasses are assigned to a particular Dominion. When an object is assigned to a dominion, a shallow copy of that object's class is made using a metaclass assigned to that Dominion. The object is then changed to be of this new class.
  • It is possible to add an instance variable called "dominion" to every single object in an image.
  • It would be possible to modify the VM to group objects of a single dominion together in memory and provide VM primitives to return the dominion of a particular object. This would require extensive changes.
  • It would be possible using a global dictionary and clever use of the tracing technology that ImageSegments uses to store knowledge about which objects belong to which dominions.
  • It would be possible to make programmers manually implement dominions. In the same way that Java has a doPrivileged() method, a method could be added to BlockContext that will mark the current thread as now "entering" a particular dominion. The programmer would have to use this method at every entry point on a particular API and would need to store that dominion.

 

Finding the active Dominion

 

The active dominion will need to be accessed when:

  • The scheduler is invoked and adds accounting information to the dominion that just ran.
  • A new object is created or released (i.e. memory is allocated and released). New entries on the call stack are also objects.
  • A resource is accessed, such as disk or network.

 

 

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.

 

Resource allocation

 

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

 

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:

  • Total number of instructions allowed before this dominion is halted.
  • Minimum and maximum total number of batch or real-time instructions per second allowed. (Does it make sence to specify a maximum number of batch instructions per second?)
  • Maximum/minimum batch/real-time CPU priority of this dominion.

 

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.

 

CPU Scheduling

 

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

 

Network usage is like CPU usage but more complicated. More thought needed here.

 

Memory

 

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

 

Disk can be allocated by specifying the maximum size and minimum size requirements needed to run. This is similar to memory.

Resource balancing

 

All these resources need to be shared evenly between all hosted dominions based on priorities.

 

Usage notifications

 

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.

 

 

Resource theft

 

Preventing resource theft

 

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?

  • Maybe the dominion is only passed out in invocations on other objects?

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.)

 

Means of resource theft

 

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.

 

Shared Variables

 

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.

 

Keeping Dominion references secure

 

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?

 

Managing Dominions

 

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:

  • Adding or removing capabilities.
  • Destroying that dominion, removing all objects from this computer.
  • Adding child domininions.
  • Re-assinging objects to other dominions (?)

 

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.

 

Handling exceptions

 

What happens when the dominion's resources are exhausted?

 

  • The process which attempts to use more resources raises an exception, or is suspended (or both if that is possible - can you resume from a thrown exception?). When the resource shortage has been resolved, the process may continue.
  • Perhaps a representative object of the dominion could be asked to reduce resource usage when there is e.g. only 5% of resources left.

 

What happens when the dominion resources are reduced to below the limits set?

 

  • Perhaps some message could be sent to a representative object of the dominion asking it to reduce resources.
  • Deadlock may occur if the dominion needs to allocate more resources in order to reduce it's resource usage.

 

What happens when a dominion is forcefully removed?

 

  • All references to objects in that dominion are nullified... somehow. A primitive could be implemented to do this, or all objects in that dominion could have a becomeForward: performed on them. These objects could be replaced with a special instance of, for example, RemovedObject or InvalidObject.
  • All threads with objects from that dominion on their call stack will need to return or be terminated.
  • Before this happens, it would be polite to inform the dominion manager (and replication algorithms) that that dominion is about to be removed? If a dominion is well-behaved, it will be able to remove itself from a VM. If it is naughty, then that dominion will need to be forcefully removed.
  • What happens if the dominion has a lock on other objects, such as system resources? What happens if a dominion's code actually is deadlocked somewhere? Removing it won't resolve the deadlock...

 

Nested Dominions

 

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.

 

Network security

 

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.

 

Using Dominions

 

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.

 

Example

 

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:

  • The Site would react to events and process them. This includes the event that calls onDraw:.
  • The Site may fork more background processes to do work.

 

These are the basic requirements for dominion-based management:

 

  • When the Site is activated, the dominion that it resides in is granted resources by the SiteBrowser.
  • The Site's CPU usage would be scheduled according to the dominion's statistics.
  • The Site's memory usage is constrained by the dominion's statistics.
  • When the Site draws on the screen (a primitive), the CPU usage is also added to the dominion's statistics.
  • If the Site uses network or disk, these are done according to the dominion's statistics.
  • When the Site is no longer used, the dominion's privileges are revoked.

 

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.

 

 

Issues

 

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.

 

  • Perhaps at scheduling time, a call stack can be measured up. If it is large (or growing, or something), then memory allocation can be tallied up.

 

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.

 

  • Perhaps the object heirarchy could have dominioned objects and non-dominioned objects (e.g. SmallInteger and Classes). Non-dominioned objects are transparent and cause a search down through the call stack.

 

 

 


Page Information

  • 2 months ago [history]
  • View page source
  • You're not logged in
  • No tags yet learn more

Wiki Information

Recent PBwiki Blog Posts