Issott_Common Design Patterns for Symbian OS-The Foundations of Smartphone Software_0470516356 (779879), страница 52
Текст из файла (страница 52)
Another potential problem with Quarantine (seepage 260) is that it works best when plug-ins are used infrequently274SECURITYbecause the overhead of creating a new process for each use will becomeprohibitive.ExampleExamples of this problem often come from components that have usedBuckle (see page 252) but have later found that the constraints it imposesare unacceptable.
This can be because the framework doesn’t providesufficient capabilities to satisfy a new plug-in or that the time and cost ofsigning sufficiently trusted plug-ins is found to be too high.One such example was the SyncML subsystem which implementsa platform-independent information synchronization standard [OMA,2002]. In particular, it contains a process called the Sync Agent whichsynchronizes the data on a device with the data on a remote server. A dataprovider interface is used to support the synchronization of data sources,such as the contacts and calendar databases, on the device. Since suchdata sources vary from device to device or could even be installed at runtime, the interface is required to be implemented by plug-ins.In an early version of the SyncML subsystem, data provider plug-inswere implemented as ECom plug-ins and loaded into the Sync Agentprocess as per Buckle (see page 252). However, as this process usedmore than just the user-grantable capabilities this made it difficult forthird parties to provide plug-ins and so an alternative design was neededin which plug-ins aren’t unnecessarily forced to have at least the samecapabilities as the framework.
Quarantine (see page 260) could have beenused to resolve the capability-mismatch issue but that approach doesn’tsatisfy the need for frequent communication between the framework andits plug-ins carrying potentially large amounts of data.SolutionThis solution allows plug-ins to execute at a different level of trust to theframework but to still maintain ongoing communication between the two.This is achieved by executing plug-ins within separate processes from theframework which therefore execute in separate memory spaces from eachother.
What makes this pattern different from Quarantine (see page 260) isthat instead of the framework process using the RProcess::Create()API to pass information once to a plug-in, it makes calls on a local proxythat forwards messages over IPC to a plug-in. Similarly, when a plug-inwishes to respond it makes calls on its local proxy which then forwardsthe response over IPC to the framework.This is reflected in the name of the pattern because the plug-ins arewrapped in cotton wool and as much as possible is done for them in theircradle. The analogy though doesn’t fully convey the security risk plug-inscould pose.Note that this secure plug-in pattern is used only occasionally.CRADLE275StructureThe main components involved in this pattern (see Figure 7.12) are:• Plug-in Client, which uses the functionality provided by the plug-ins• Framework proxy, which forwards the local function calls made onit by a framework proxy over IPC to the cradle process; there is oneframework proxy per plug-in• Plug-in proxy, which forwards the local function calls made by aplug-in to it over IPC to the framework process; there is one plug-inproxy per plug-in• Plug-ins, which are hosted in one of the cradle processes so thatthey are separated from the framework whilst still providing theconfigurable functionality needed by the framework.Figure 7.12 Structure of the Cradle patternAll components are supplied by the framework provider with theexception of the plug-ins, of course.
This is so that these components onlyhave to be written once and can then be re-used for each of the plug-ins.Note that the two proxies in Figure 7.12 make it appear to theirrespective clients as if making calls on them is exactly like making callson the eventual recipient of those calls in the other process. This isachieved by each proxy implementing the interface of the intended targetand simply forwarding the messages on exactly as in the Proxy pattern[Gamma et al., 1994]. The main advantage of this is that the clients ofthe proxies do not need to have any knowledge of where the recipientresides nor any knowledge of the exact mechanism for communicatingover IPC.
This simplifies the implementation and allows more flexibilityin the architecture.The exact packaging of this pattern depends on the capabilities youexpect the plug-ins to use. The problem is that capabilities are set atcompile time, not run time, so when creating the extension point, theframework provider needs to decide which cradle EXEs with whichcapabilities to provide before any plug-ins exist:• If you expect all plug-ins to have the same capabilities then only asingle cradle EXE with this set of capabilities needs to be provided.276SECURITY• If you expect the plug-ins to have a wide variety of capabilities, thenyou will need to carefully choose which cradle EXEs with whichcapabilities to provide. Ideally, a cradle EXE would be provided foreach set of capabilities required by a plug-in but this could quicklybecome unmanageable36 and you may need to compromise andprovide a reduced set of cradle EXEs.
The trade-off is that someplug-ins would have to be signed with capabilities they don’t needsimply because there isn’t a cradle EXE that exactly matches theirrequired capability set which may mean additional time and cost forplug-in providers. However, a good choice of cradle EXEs that keepsin mind the different types of capabilities (user, system, restrictedsystem, device-manufacturer-approved) should minimize this impact.Having decided which cradle EXEs need to be supplied, the frameworkprovider needs to decide whether or not to host multiple plug-ins ina single cradle process.
Irrespective of how many cradle EXEs youhave, it is possible to host each plug-in in its own process simply byusing the appropriate cradle EXE to create another instance of a processwhen each new plug-in is loaded. From a security point of view, thisis a preferred option since each plug-in is completely isolated frominterference from other plug-ins. The problem with that approach is, ifyou need to have multiple plug-ins loaded at once, this might have asignificant RAM overhead37 since each process will consume a defaultminimum of at least 21–34 KB.38 If this is a significant problem thenhosting multiple plug-ins in a cradle process is the only way to reducethis.The rest of this pattern assumes that there could be multiple cradleEXEs each used to create a process hosting several plug-ins.
This thencovers the other possibilities as degenerate cases.Interestingly, this pattern can be seen as the inverse of the Secure Agent(see page 240) in that we are separating out the less trusted componentsinto their own processes.DynamicsFigure 7.13 shows the two main sequences – loading a plug-in and making use of it. In Figure 7.13, RProcess::Create() is shorthand for thefull process start-up sequence described in Quarantine (see page 260).An actual plug-in is loaded by the cradle process using Buckle (seepage 252).36 Since there are currently 20 different capabilities this means there are 220 distinctcapability sets possible.37 There is also the execution time overhead of creating a process though this is lesslikely to be significant and you may be able to use a pattern from Chapter 3 to address theproblem without compromising security.38 See Appendix A for more details.CRADLECradle ProcessFramework ProcessFramework ProxyPlug-in Client277Plug-in ProxyEComPlug-inListPlugins()seq Load Plug-in[For each valid plug-in]Loadplugin()[Cradle Process Doesn’t Exist]:RProcess::Create()CreateImplementationL(PluginUid)CreateImplementationL(PluginUid)[Check Failed]:KErrPermissionDenied[Check Succeeded]:Proxy Object[Check Failed]:KErrPermissionDenied[Check Succeeded]:KErrNone[Check Failed]:KErrPermissionDenied[Check Succeeded]:Plug-in ObjectCapabilityCheck()[Check Succeeded]:Load()seq Plug-in UsageServiceRequest()ServiceRequest()«RequestComplete»ServiceRequest()«RequestComplete»«RequestComplete»Figure 7.13Dynamics of the Cradle patternWhen loading a plug-in, the plug-in client ensures itself that it is loadinga sufficiently trusted plug-in via the following authentication chain:1.
The plug-in client can trust the framework proxy because they residein the same process and hence must both have been assigned thecapabilities of their process.2. The framework proxy has the opportunity when creating a plug-inprocess, and hence the plug-in proxy, to authenticate it using itscapabilities, SID, or VID just as is done in Quarantine (see page 260).3. The plug-in proxy relies on the DLL loading rule to prevent it fromloading plug-ins that do not have at least the capabilities of theplug-in process.A plug-in can be sure it has been loaded by a trusted framework due tothe following authentication chain:1.
Any untrusted process would not be able to execute with the necessary capabilities needed by a plug-in to perform its activities.278SECURITY2.The plug-in process, hence the plug-in proxy, has the opportunity toauthenticate its creator just as is done in Quarantine (see page 260).3.The framework proxy can trust the plug-in client because they residein the same process and hence must both have been assigned thecapabilities of their process.ImplementationFrameworkThe first thing to do is to determine which capabilities might be requiredby the plug-ins.
This will then allow you to choose the number and thecapabilities of the cradle EXEs needed. Note that you should be cautiousin providing cradle EXEs at different levels of trust (i.e. with differentcapabilities) to avoid over-complicating the implementation. In addition,this architecture is easily extended with additional cradle processes infuture if needed.If more than one cradle EXE is required for your framework, then youneed to choose a mechanism by which plug-in providers can specifywhich of the cradle processes their plug-in should be loaded into. Oneway this can be achieved is by requiring plug-in providers to supply twodifferent files:1.A resource file that tells the framework which cradle process shouldbe used to load a plug-in.