MOBILE

Mobile Application Security : SymbianOS Security - Code Security

2/19/2011 5:36:09 PM
The primary development language for SymbianOS is a modified dialect of C++ known as Symbian C++; however, additional language runtimes are available. Developers may opt to write applications with P.I.P.S (P.I.P.S Is Posix on SymbianOS), Open C (an extension of P.I.P.S.), Python, Java, or other languages. In general, additional runtimes do not come preinstalled, and the runtime installer should be embedded within the installers of relying applications.

Symbian C++

With Symbian C++, code executes directly on the hardware of the phone, without a virtual machine or interpreter, allowing a developer to take full advantage of the available resources. Unfortunately, such native code does not provide protections against many common memory corruption vulnerabilities. This includes stack overflows, heap overflows, and integer overflows. In essence, the programmer is entirely responsible for preventing these vulnerabilities through appropriate secure coding practices. Otherwise, an attacker could potentially cause their malicious code to execute within an exploited process.

Descriptors

Symbian provides technologies to reduce the chances of exploitable buffer overflow conditions, but the programmer must take advantage of them. For example, buffer overflows regularly result from mishandling data when copying, formatting, or concatenating strings and byte arrays. To protect against such errors, Symbian C++ provides the descriptor framework to replace all C-style strings and the related string-handling operations. They are called descriptors because each instance stores its type, length, and data, thus describing everything needed to safely manipulate the stored data. Mutable descriptors (those whose name does not end with the letter C) also include the maximum length. Figure 1 presents the relationships among the varied descriptor classes.

Figure 1. Relationships among the Different Descriptor Classes

Descriptors come in both 8-bit-wide and 16-bit-wide varieties and can be identified by the number appended to the name (for example, TDesC8 and TBuf16). When a descriptor is used that includes neither a 16 nor an 8, the 16-bit version will be used. (Technically a determination is made based on whether the _UNICODE macro is defined, which is the platform default.)

It is important to note that the type and the length are stored within a single 32-bit Tint field. The four most significant bits indicate the type of the descriptor, and the remaining 28 bits represent the size of the referenced data. This has several important consequences. First, descriptors are limited to a maximum size of 256MB (228 bytes). Second, developers must be exceptionally careful deriving custom descriptor subclasses with regard to the type field. The TDesC base class uses this field to determine the memory layout of its subclasses. This means that custom subclasses cannot have an arbitrary memory layout, but must share a type and memory layout of a built-in descriptor. It is not recommended to derive custom descriptor classes.

For example, accessing the descriptor data of each subclass is performed with the non-virtual Ptr() method defined in the TDesC base class. (In fact, there are no virtual methods within the descriptor hierarchy.) This method uses the type data stored in each descriptor instance as the control variable for a switch statement that then returns the proper address referring to the beginning of the data.

By preserving the length (and maximum length) of a descriptor, its method calls are able to perform appropriate validation and prevent the unintentional access to out-of-bounds memory. When a method call would read or write beyond the data boundaries, the process will panic and immediately terminate. This means that with traditional descriptors, the burden of correct memory management falls solely on the shoulders of the developer. They must verify that the descriptor can accommodate the amount of incoming data before calling a method that would modify the contents of the descriptor.

Recognizing these difficulties, Symbian has developed and released a new library. The EUserHL Core Idioms Library provides a pair of descriptors (LString for Unicode-aware text and LData for simple byte buffers) that manage their own memory. These descriptors automatically reallocate themselves to increase their capacity and then release the resources when they go out of scope, similar to the behavior of standard C++ strings. Because these two classes have been derived from their respective TDesC class (TDesC8 and TDesC16), they can be used as parameters directly when accessing the preexisting platform API. LString and LData should be used instead of any of the other descriptor classes.

Caution

Because descriptor methods are not virtual, preexisting methods in the class hierarchy will still cause a process panic when the buffer is not large enough to hold the fresh data. For working with LString and LData directly, these methods have been restricted with the private access modifier and public replacements have been introduced. These can be identified by the “L” suffix common to all API functions that may leave (throw an exception). However, LString or LData objects passed to a function taking TDes16 or TDes8 parameters will not have the new methods called. You should ensure that the LString/LData object is large enough to hold any resultant data when calling such a method. The ReserveFreeCapacity method should be called before calling any such method.


Arrays

Memory management issues can also arise when manipulating bare arrays. After all, a C-style string is a null-terminated array of chars. Rather than use a C-style array (int a[10]; int * b = new int[10];), Symbian provides many classes for safe array management. In fact, the number of separate classes available can be daunting.

For the predominant use cases, the RArray and RPointerArray template classes are the recommended choices. These two classes manage their own memory and implement a traditional array interface (that is, indices can be accessed through the [] operator, and objects can be inserted, deleted, and appended). Attempts to access indices outside the bounds of the current size (either negative or greater than the current size) will cause the process to panic.

Using the RArray class has some additional restrictions that RPointerArray is not subject to. Due to an implementation detail, objects stored in an RArray class must be word-aligned on a four-byte boundary and cannot be larger than 640 bytes. Attempts to create an RArray of objects larger than 640 bytes will cause the process to panic. In these cases, consider using an RPointerArray instead. Here’s an example:

LString ex1 (_L ("example1")), ex2(_L ("example2"));
LCleanedupHandle< RArray< LString > > strArray;
strArray->ReserveL(10);
strArray->AppendL(ex1);
strArray->InsertL(ex2, 0);
strArray->Remove(0);
strArray->Compress();

Integer Overflows

Symbian does not provide for automatic protections against integer overflows. An integer overflow occurs when the memory representation of an integer variable lacks the capacity to hold the result of an arithmetic operation. The behavior when such a condition arises is left as an implementation-specific detail. Integer overflows can cause security vulnerabilities in many instances—for example, when allocating memory or accessing an array. Developers must consciously take strides to eliminate the risk associated with such errors. As such, each arithmetic operation should be checked for overflow conditions.

When a type is available whose representation is twice as large as the type that is to be checked—for example, a 64-bit integer and a 32-bit integer—the overflow tests are straightforward. This is because the larger type can accurately hold the result of any arithmetic operation on variables of the smaller type. Symbian provides both a signed and an unsigned 64-bit integer type that can be used to perform such testing:

TInt32 safe_add(TInt32 a, TInt32 b) {
TInt64 c = static_cast< TInt64 >(a) + b;
if((c > INT_MAX) || (c < INT_MIN)) {
User::Leave(KErrOverflow);
}
return static_cast< TInt32 >(c);
}

If the parameters to an arithmetic operation are known at compile time (for example, using literals and constants), then the GCCE compiler will be able to flag the potential integer overflows—GCCE being one of the compilers that targets the physical phone. Each of these should be reviewed to ensure that the overflow does not cause an issue. Note that the four SID and the four VID security policy macros will trigger a false positive integer overflow and can be safely ignored.

Leaves and Traps

SymbianOS has a system known as leaves and traps for handling many error conditions. Calling User::Leave(TInt32 ErrorCode) is directly analogous to the throw statement from standard C++, and the TRAP/TRAPD macros take the place of the try/catch statements. (The TRAP macro requires the developer to explicitly declare an error code variable, whereas the TRAPD macro does this automatically.) A function that could potentially cause such an error is referred to as a function that “may leave.” These can be identified in the standard library through a naming convention—each function whose name ends with a capital L can potentially leave.

In older versions of Symbian, these could be imagined as being implemented using the setjmp and longjump pair of functions. This means that program flow could jump from one function to another without performing appropriate stack cleanup; the destructors for stack objects were not executed. This necessitated implementing a custom system for managing heap allocated memory in order to prevent memory leaks. This system is called the Cleanup Stack. Every time a developer allocates an object on the heap, a reference should be pushed onto the cleanup stack. Whenever an object goes out of scope, it should be popped off the cleanup stack and deallocated. If a function leaves, all objects on the current cleanup stack frame are removed and deallocated. The beginning of a stack frame is marked by the TRAP/TRAPD macros and can be nested.

Another consequence of the abrupt transfer of program flow control was that constructors could not leave. If they did, the partially constructed object would not be properly cleaned up because the destructor would not be called and no reference had been pushed onto the cleanup stack. In order to get around this, many classes implement two-phase construction, where the actual constructor does nothing but return a self-reference and a second method ConstructL initializes the object. These methods are oftentimes private. Instead, classes offer a public method, NewL or NewLC, that creates an object, initializes it, and returns a reference.

In the 9.x series of SymbianOS, the leaves and trap system has been implemented on top of standard C++ exceptions. When a function leaves, several steps are performed:

  1. All objects in the current frame of the cleanup stack are removed and deallocated, calling any object destructors.

  2. An XLeaveException is allocated and thrown. This exception will be created using preallocated memory if new memory cannot be obtained (for example, during an out-of-memory condition).

  3. Through the standard C++ exception procedure, the call stack is unwound and the destructor is called on each stack object.

  4. One of the TRAP/TRAPD macros catches the thrown exception and assigns the error code to an integer variable that a developer should test. Any other type of exception will cause the process to panic.

This backward compatibility has several interesting consequences. First, a developer should never mix the use of standard exceptions and SymbianOS leaves. A function that leaves should not call a function that throws exceptions without enclosing it within a try/catch block in order to prevent propagation back to a TRAP macro. Similarly, any function that may leave called from code using only standard exceptions should be wrapped with one of the TRAP/TRAPD macros.

When leaves and traps were mapped onto the standard exception mechanism, the use of two-phase construction remained. With the release of the EUserHL Core Idioms Library, you may return to a more traditional Resource Acquisition Is Initialization (RAII) model. When you define a new class, you should use the CONSTRUCTORS_MAY_LEAVE macro as the first line of code. This macro actually defines how the delete operator will affect the class:

class CUseful : public CBase {
public:
CONSTRUCTORS_MAY_LEAVE
CUseful ();
~CUseful();
};

Finally, the use of a cleanup stack continued to be useful because there were several classes that did not adequately clean up properly upon destruction. These objects required the developer to explicitly call a cleanup method—generally Close, Release, or Destroy. The EUserHL Core Idioms Library also includes a set of classes to assist the developer with proper resource management in these cases. This includes the LCleanedupXXX and LManagedXXX classes. The LCleanedupXXX group of classes, found in Table 1, is designed for use with local function variables, and the LManagedXXX group of classes, found in Table 7-2, is designed for use with class member variables.

Table 1. Local Variable Automatic Resource Management
Class NamePurpose
LCleanedupPtrManage object pointers.
< typename T >Free memory when leaving scope.
LCleanedupHandleManage resource objects (e.g., RFs & rfs).
< typename T >Call Close() when leaving scope.
LCleanedupRefManage a reference to a resource object (e.g., RFs & rfs).
< typename T >Call Close() when leaving scope.
LCleanedupArrayManage an array of object pointers.
< typename T >Free all memory when leaving scope. (Prefer RArray.)
LCleanedupGuardAutomatic management of generic objects.

Table 2. Class Member Variable Automatic Resource Management
Class NamePurpose
LManagedPtrManage object pointers.
< typename T >Free memory when leaving scope.
LManagedHandleManage resource objects (e.g., RFs & rfs).
< typename T >Call Close() when leaving scope.
LManagedRefManage a reference to a resource object (e.g., RFs & rfs).
< typename T >Call Close() when leaving scope.
LManagedArrayManage an array of object pointers.
< typename T >Free all memory when leaving scope. (Prefer RArray.) LManagedGuard Automatic management of generic objects.

These classes implement what can be viewed as a set of “smart pointers.” The developer no longer has to worry about pushing and popping objects from the cleanup stack, deleting memory before a reference goes out of scope, or calling a resource cleanup function. This is all performed appropriately when one of the LManagedXXX/LCleanedupXXX objects goes out of scope. In the following example, the handle to the file server and to an open file are automatically closed and released when the function ends:

void readFileL(LString filename, LString data) {
LCleanedupHandle<RFs> fs;
LCleanedupHandle<RFile> file;
TInt size;

fs->Connect() OR_LEAVE;
file->Open(*fs, filename, EFileRead) OR_LEAVE;
file->Size(size) OR_LEAVE;

data.SetLengthL(0);
data.ReserveFreeCapacityL(size);

file->Read(data) OR_LEAVE;
}

And in the following example, the CMessageDigest object that is allocated in the constructor of the CUseful class is automatically cleaned up when an instance goes out of scope. The destructor does not need to do anything to prevent memory leaks.

class CUseful : public CBase {
public:
CONSTRUCTORS_MAY_LEAVE
CUseful
() : hash(CMessageDigestFactory::NewHMACL (
CMessageDigest::ESHA1, HMACKey)) { }
~CUseful(){ }

private:
LManagedPtr< CMessageDigest > hash;
};

The different groups of classes, LCleanedupXXX and LManagedXXX, arise due to interaction with the cleanup stack. Indeed, if the LCleanedupXXX classes were used for class member variables, then objects would be popped and destroyed from the cleanup stack out of order.

Use of these classes is recommended in order to reduce the possibility of manual memory management errors, such as memory leaks, double frees, null pointer dereferences, and so on.

Automatic Protection Mechanisms

SymbianOS does not guarantee the presence of any automatic protection mechanisms to mitigate memory corruption vulnerabilities. Neither address space layout randomization nor stack canaries are available in any form. A nonexecutable stack is only available when run on hardware that supports it—namely, ARMv6 and ARMv7, but not ARMv5.

Although such mechanisms are not perfect in preventing the exploitation, they do increase the level of skill required to craft a successful exploit. Because they are not present, developers must continue to be exceptionally careful to reduce the risk of code execution vulnerabilities.

P.I.P.S and OpenC

P.I.P.S. is a POSIX compatibility layer that aides in the rapid porting of software to SymbianOS-based phones. OpenC is an S60 extension of P.I.P.S. that brings a larger set of ported libraries. These environments are not suitable for GUI code, which must continue to be written in Symbian C++.

P.I.P.S. and OpenC are implemented as shared libraries that are linked into native code applications. This means that applications written for either of these environments suffer from all of the same memory corruption flaws. In fact, it is more likely to have such problems because the environment does not provide safer alternatives—namely, descriptors and array classes. As such, string handling is performed with C-style strings and the associated set of blatantly unsafe functions, such as strcat and strcpy.

P.I.P.S. and OpenC should only be used for POSIX code ported from other platforms, not for newly written code for the SymbianOS platform.

Other  
  •  iPhone Application Development : Getting the User’s Attention - Generating Alerts
  •  iPhone Application Development : Getting the User’s Attention - Exploring User Alert Methods
  •  iPhone Application Development : Using Advanced Interface Objects and Views - Using Scrolling Views
  •  Working with the Windows Phone 7 Application Life Cycle (part 2) - Managing Application State
  •  Working with the Windows Phone 7 Application Life Cycle (part 1) - Observing Application Life Cycle Events
  •  Mobile Application Security : SymbianOS Security - Development and Security Testing
  •  Mobile Application Security : SymbianOS Security - Introduction to the Platform
  •  Java Mobile Edition Security : Permissions and User Controls
  •  Integrating Applications with the Windows Phone OS : Working with Launchers and Choosers
  •  Introducing Windows Phone 7 Launchers and Choosers
  •  Java Mobile Edition Security : Development and Security Testing (part 3) - Code Security & Application Packaging and Distribution
  •  Java Mobile Edition Security : Development and Security Testing (part 2) - Reverse Engineering and Debugging
  •  Java Mobile Edition Security : Development and Security Testing (part 1) - Configuring a Development Environment and Installing New Platforms & Emulator
  •  Java Mobile Edition Security : Configurations, Profiles, and JSRs
  •  Programming the Mobile Web : Performance Optimization
  •  Programming the Mobile Web : Testing and Debugging (part 3) - Client-Side Debugging
  •  Programming the Mobile Web : Testing and Debugging (part 2) - Server-Side Debugging & Markup Debugging
  •  Programming the Mobile Web : Testing and Debugging (part 1) - Remote Labs
  •  Windows Phone 7 : Working with Controls and Themes - Adding Transition Effects
  •  Windows Phone 7 : Working with Controls and Themes - Understanding Frame and Page Navigation
  •  
    Top 10
    Sapphire Pure Platinum A85XT - Sensible Smattering Of Features
    SSD Supertest – December 2012 (Part 6)
    SSD Supertest – December 2012 (Part 5) : Samsung 840 250GB, Samsung 840 Pro 256GB
    SSD Supertest – December 2012 (Part 4) : OCZ Vertex 4 256GB, Plextor M5 Pro 128GB
    SSD Supertest – December 2012 (Part 3) : KingSpec PCIe MultiCore 1TB, Kingston HyperX 3K 120GB
    SSD Supertest – December 2012 (Part 2) : Intel 330 Series 180GB
    SSD Supertest – December 2012 (Part 1) : Corsair Neutron 240GB, Corsair Neutron GTX 240GB
    Synology DS213+ - Great Features, But Expensive
    Thermaltake Level 10m - The BMW Gaming Mice
    ZOTAC GTX 650 TI – It’s Time To Play
    Most View
    Asus X501A - Thin And Light Design For Your Personal Expression
    Personalize Your iPhone Case
    SharePoint 2010 : Outlining the Inherent Threat in SharePoint Web Traffic
    Displacement Maps
    Google’s Data Liberation Front (Part 2)
    The big test … Inter Core Power (Part 2) - Asus Zenbook UX31E & Dell XPS 14z
    How To Automate Your Web With ifttt (Part 1)
    HP Photosmart 5510 e-All-in-One Printer
    OData with SQL Azure - Enabling OData on an Azure Database
    Algorithms for Compiler Design: DATA STRUCTURES FOR REPRESENTING PARSING TABLES
    Recommended Buys: Everyday Computing – November 2012
    Asus X53z
    The New Sheriff In Town
    Which Is The Real Best-Seller Ultrabook? (Part 1) - Asus Zenbook Prime, Acer Aspire S5, HP Folio 13-2000
    Exchange Server 2007: Design and Deploy Disaster Recovery Settings - Implement Database Portability
    Gioteck HF-2 Controller - Different Strokes
    Managing Exchange Server 2010 : The Exchange Management Shell (part 2) - Remote PowerShell
    The Pick Of Windows 8 Metro Apps (Part 2)
    HP Global Influencer Summit 2012 (Part 2) - HP Photosmart 5520 e All-in-One, HP t410 AIO
    Google’s Data Liberation Front (Part 1)