1. Problem
1.1. Context
You need to provide a simple-to-use but secure
extension point in your component to easily allow future upgrades or
customization.
1.2. Summary
1.3. Description
A plug-in is a component loaded into a framework at
run time so as to provide a certain, usually very specific, function.
Frameworks support plug-ins for many reasons which include:
One possible way to achieve this is by having a
configuration file that allows new settings to be specified after a
component has been released. However, this is normally quite restrictive
and so a mechanism by which additional code can be plugged in is
needed.
This problem is seen by all types of developer whether they're a device creator or a third-party application developer.
1.4. Example
If you are creating a service for a mobile phone,
then it's unlikely that your code will include a full graphical UI.
Despite this, there are occasions where you still need to be able to
display notifications and prompts to the end user. For instance, when
the Messaging subsystem detects that an SMS has been received, it needs
to be able to alert the user with a 'Message received' notification.
To help fulfill this requirement, Symbian OS provides a Notification Server that exposes the RNotifier API. However, whilst this works for a number of use cases, it doesn't support:
Clearly, to support the above, the Notification
Server needs to be extensible. However, to allow untrusted code to
provide dialog plug-ins would mean that a malicious attacker could
deliberately attack the Notification Server by creating a high-priority
notifier which monopolizes the screen. This would prevents any
lower-priority notifiers from being activated and potentially make the
device unusable: the extension point needs to be protected from being
misused.
2. Solution
Use the ECom service
to provide the general extension point functionality of selecting and
loading plug-ins as DLLs that expose the plug-in interface specified by
your framework. This forces plug-ins to have the same capabilities as
the framework itself.
The name of the pattern reflects this purpose:
buckles are about joining two objects together (pieces from two
different buckles can't be connected together) and they're used in seat
belts to keep people secure.
Note that this is the most frequently used of all the secure plug-in patterns.
2.1. Structure
This pattern has the simple structure shown in Figure 1.
Once each plug-in is loaded, it resides within the
framework process and can be used exactly as if it had been statically
linked to during development. However this structure has significant
security implications:
A plug-in must satisfy the DLL loading rule
or it cannot be loaded into the framework process. This rule states that
the plug-in DLL must have the same, or a superset of, the capabilities
of the loading process.
You have chosen to welcome
the plug-in into your process and hence do not get any of the benefits
of memory isolation offered by executing in a different process. It
means that a plug-in has access to any memory used by the framework
since Symbian OS only enforces memory isolation between processes. It also means that once loaded no further security checks can be made by the framework on a plug-in.
Calls
by a plug-in to other processes can be authenticated as normal.
However, these checks are made on the credentials of the framework
process and not anything specified by the plug-in provider.
It
is not possible to authenticate a plug-in by an SID or VID as these are
properties of a process at run time and not of code in a DLL.
As far as security is concerned everything hinges on
the capabilities you, as the framework provider, assign to the framework
process. When you assign these capabilities you should follow these
guidelines:
Assign the minimum set of capabilities needed (principle of least privilege).
Assign the capabilities required by the framework to meet the security policies imposed by the APIs it calls.
Assign the capabilities required by a plug-in to meet the security policies imposed by the APIs it calls.
Do
not assign a capability solely to impose an additional restriction on
who can provide a plug-in to your framework because whilst this may
appear to work there are situations in which it can be subverted.
In the advent of someone trying to spoof the
framework this structure does not prevent a plug-in from being loaded.
Assuming the plug-in can be loaded then it'll be run with the
capabilities that the loading process has been able to obtain. The
platform security architecture of Symbian OS allows us to assume that
the loading process has obtained its capabilities legitimately. Hence it
can only run the plug-in successfully if it has been trusted with the
capabilities used by the plug-in when calling APIs and no advantage is
gained by the spoof framework.
2.2. Dynamics
It is when a plug-in is loaded that the security
check on the plug-in occurs. A plug-in is only successfully loaded if
the plug-in's DLL has at least each of the capabilities assigned to the
framework EXE. Once loaded, a plug-in is within the process' isolation
boundary and will potentially have access to all memory and resources of
the framework process. No further security checks can be performed on
it after this point.
Plug-in selection is performed via the ECom service which resides in the ECom server process (see Figure 2)
and hence involves a context switch when the plug-in is loaded.
However, once the ECom plug-in has been selected it acts just as if the
DLL providing the plug-in was loaded directly into the process and has
the same performance benefits as statically loaded DLLs.
The framework can use the REcomSession::ListImplementationsL()
API to find plug-ins that have implemented the plug-in interface
specified by the framework provider. For usability reasons, it only
returns references to plug-ins that would satisfy the DLL loading rule
for the framework process. Whilst this might seem to make the CreateImplementationsL() security check unnecessary, it avoids a Time-of-Check-Time-of-Use (TOCTOU) security hole since a client can pass any plug-in UID into CreateImplementationsL().
2.3. Implementation
Framework
One of the early decisions that framework providers
need to make when using this pattern is what capabilities they should
require plug-ins to have.
Note that this decision has important consequences for who can provide
plug-ins and the cost associated with doing so.
Once the decision has been made on what the
capabilities of the framework will be, the developer of the framework
should assign them to the EXE:
// Framework.mmp
TARGET framework.exe
TARGETTYPE exe
UID 0xE8000077
CAPABILITY <capability list>
SOURCEPATH .
SOURCE framework.cpp
USERINCLUDE .
SYSTEMINCLUDE \epoc32\include
SYSTEMINCLUDE \epoc32\include\ecom
LIBRARY euser.lib
LIBRARY ecom.lib
For more details of the MMP file syntax, see the Symbian Developer Library.
Plug-ins
A plug-in developer should assign the same
capabilities as used by the framework process, unless there's a very
good reason to add more, to the plug-in's MMP file to be successfully loaded by the framework at run time.
Other than this, a plug-in should be implemented exactly as specified by the ECom service.
2.4. Consequences
Positives
This pattern is simple to understand, which reduces maintenance costs.
It
is easy to implement the security checks in the framework since it
could be as little as one extra line in an MMP file compared to not
having any checks at all.
There is no
impact on performance or memory usage except for a small overhead when
the plug-in is loaded compared to statically linking to it.
Negatives
The security check is all or nothing.
Once
a plug-in has been loaded, it can access any data that the framework
process can access and hence is able to affect its behavior.
If
the framework process requires additional capabilities to perform its
own tasks then this may result in unnecessary security requirements
being placed on the plug-ins.
Adding more
capabilities to the framework executable is, at best, difficult. This
is because all plug-ins would also need to have this new capability or
the framework will no longer be able to load them. The more plug-in
providers there are, the more of a problem this is. In practice, adding
more capabilities after a framework has been released isn't feasible. If
you think you might need to do this then use Quarantine (see page 260) or Cradle (see page 273).
Any
plug-ins with more capabilities than the framework process cannot use
them since a plug-in DLL is limited at run time to just the capabilities
assigned to the framework process.
2.5. Example Resolved
The Notification Server resolves its need for secure
plug-ins by using the ECom service to identify and load plug-ins
directly into the eiksrvs.exe process. The server requires the
TrustedUI capability to allow it to display dialogs to the user that
won't be misleading or somehow corrupt the UI. In addition, the process
requires the ProtServ capability to allow it to register the
Notification Server within a protected name space and so limit the scope
for the server to be spoofed.
The result of this is that dialog plug-in providers
must create an ECom plug-in DLL which implements a custom notifier class
by deriving from MEikSrvNotifierBase2. For the DLL to successfully load into the eiksrvs.exe process, it must have the same capabilities as the process (TrustedUI and ProtServ)
or more. Since both of these are system capabilities, some additional
development time is required of plug-in providers to achieve this but no
additional run-time costs are incurred. Note that we would expect plug-ins to need the TrustedUI capability since it is directly related to what a plug-in does. The ProtServ
capability however, isn't needed by the plug-in though it must have it
assigned so that the framework can trust the plug-in not to subvert the
framework's own use of the capability.
The result is that third-party developers can add new
dialogs to the Notification Server but, because they are signed, any
such plug-ins that are found to be malicious could potentially have
their signatures revoked in future to prevent them from being installed
on new devices.
For more on the Symbian OS Notification Services, including notifier code examples, see [Willee, Dec 2007].
3. Other Known Uses
This pattern is widely used but we've just picked the following two examples to further illustrate it:
Y-Browser [Silvennoinen, 2007]
This
is a file browser application designed for S60 3rd edition devices. In
particular, it supports plug-ins for its 'Open With' menu option that
are loaded using the pattern. The framework process is created when YuccaBrowser.exe is executed, which uses ECom to locate any plug-ins that have at least the following capabilities: Network-Services, LocalServices, ReadUserData, WriteUserData, UserEnvironment.
Since these are all user-grantable capabilities, it is relatively easy
for any third-party developer to obtain them and so extend the
functionality of Y-Browser without risking the loss of the user's
information.
Protocol Modules
Another example is the Symbian OS Communication Infrastructure, which loads protocol module plug-ins (.PRTs) into the c32exe.exe
process. This framework process has an extensive list of capabilities
of up to but not including device-manufacturer-approved grantable
capabilities which means that the providers of plug-ins won't generally
include the average third-party developer. Note that, like a number of
older Symbian OS plug-in frameworks, the Communication Infrastructure
doesn't use ECom but uses RLibrary::Load() directly.