--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debugsrv/runmodedebug/securityserver/src/c_security_svr_session.cpp Thu Sep 02 22:05:40 2010 +0300
@@ -0,0 +1,2653 @@
+// Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Provides the debug security server session implementation.
+//
+//
+
+/**
+ @file
+ @internalTechnology
+ @released
+*/
+
+// Needed so we get the text strings for capabilities
+#define __INCLUDE_CAPABILITY_NAMES__
+
+#include <e32std.h>
+#include <e32std_private.h>
+#include <e32btrace.h>
+#include <d32btrace.h>
+#include <e32base.h>
+#include <e32base_private.h>
+#include <e32uid.h>
+#include <f32file.h>
+#include <e32capability.h>
+#include <rm_debug_api.h>
+
+// required for direct parsing of e32image/tromimage headers
+#include <f32image.h>
+#include <e32rom.h>
+
+//added for direct access to media driver
+#include <partitions.h>
+#include <ftlcontrolio.h>
+
+#include "c_security_svr_session.h"
+#include "c_security_svr_server.h"
+#include "c_security_svr_async.h"
+#include "rm_debug_logging.h"
+#ifdef _DEBUG
+#include "low_mem_requests.h"
+#endif
+
+using namespace Debug;
+
+CSecuritySvrSession::CSecuritySvrSession(const TProcessId& aDebugAgentProcessId)
+ : iDebugAgentProcessId(aDebugAgentProcessId),
+ iServerNotified(EFalse),
+ iCrashConnected(EFalse)
+ {
+ // Ensure that this debug agent has no target capability override
+ // by default
+ iOEMDebugCapabilities.SetEmpty();
+ }
+
+void CSecuritySvrSession::ServiceError(const RMessage2 &aMessage, TInt aError)
+ {
+ LOG_MSG2("CSecuritySvrSession::ServiceError(), aError: %d\n", aError);
+
+ //insert ending heap markers
+ HeapWatcher(aMessage.Function(), EFalse);
+
+ aMessage.Complete(aError);
+ }
+
+/**
+Called by the client/server framework as part of session creation.
+
+Notifies the server that a session is being created
+*/
+void CSecuritySvrSession::CreateL()
+ {
+ LOG_MSG("CSecuritySvrSession::CreateL()\n");
+
+ //notify the server that the session has been opened
+ Server().SessionOpened();
+ iServerNotified = ETrue;
+ }
+
+/**
+ Returns a reference to the DSS
+
+ @return a reference to the DSS
+ */
+CSecuritySvrServer& CSecuritySvrSession::Server() const
+ {
+ return *static_cast<CSecuritySvrServer*>(const_cast<CServer2*>(CSession2::Server()));
+ }
+
+/**
+Session destructor. Performs necessary cleanup and notifies the server that the
+session is being closed
+*/
+CSecuritySvrSession::~CSecuritySvrSession()
+ {
+ LOG_MSG("CSecuritySvrSession::~CSecuritySvrSession!()\n");
+
+ // Cancel any outstanding async objects.
+ iAsyncHandlers.ResetAndDestroy();
+
+ // Inform the device driver of the agent detach.
+ Server().iKernelDriver.DetachAgent(iDebugAgentProcessId.Id());
+
+ LOG_MSG( "CSecuritySvrSession::~CSecuritySvrSession() : -> securityServer.DetachAllProcesses()\n" );
+ Server().DetachAllProcesses(iDebugAgentProcessId);
+
+ //notify the server that the session has closed
+ if(iServerNotified)
+ {
+ Server().SessionClosed();
+ }
+ }
+
+void CSecuritySvrSession::ConstructL()
+ {
+ // nothing to do
+ }
+
+/**
+ Used to insert heap checking markers.
+
+ @param aFunction The function that heap markers should be added for
+ @param aEntry if ETrue indicates that heap checking is starting, if EFalse
+ that heap checking is ending.
+ */
+void CSecuritySvrSession::HeapWatcher(const TUint32 aFunction, const TBool aEntry) const
+ {
+ switch(aFunction)
+ {
+ case EDebugServAttachExecutable:
+ return;
+ case EDebugServDetachExecutable:
+ return;
+ case EDebugServSuspendThread:
+ return;
+ case EDebugServResumeThread:
+ return;
+ case EDebugServAttachAll:
+ return;
+ case EDebugServDetachAll:
+ return;
+// used for out-of-memory testing in debug mode
+#ifdef _DEBUG
+ // start heap marking in on entry, do nothing on exit
+ case EDebugServMarkHeap:
+ {
+ if(aEntry)
+ {
+ __UHEAP_MARK;
+ }
+ return;
+ }
+ // stop heap marking on exit, do nothing on entry
+ case EDebugServMarkEnd:
+ {
+ if(!aEntry)
+ {
+ __UHEAP_MARKEND;
+ }
+ return;
+ }
+#endif
+ default:
+ if(aEntry)
+ {
+ __UHEAP_MARK;
+ }
+ else
+ {
+ __UHEAP_MARKEND;
+ }
+ return;
+ }
+ }
+
+void CSecuritySvrSession::ServiceL(const RMessage2& aMessage)
+//
+// Session service handler
+//
+ {
+ //insert starting heap markers
+ HeapWatcher(aMessage.Function(), ETrue);
+
+ switch(aMessage.Function())
+ {
+ case EDebugServResumeThread:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServResumeThread\n" );
+ ResumeThreadL(aMessage);
+ break;
+
+ case EDebugServSuspendThread:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSuspendThread\n" );
+ SuspendThreadL(aMessage);
+ break;
+
+ case EDebugServReadMemory:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServReadMemory\n" );
+ ReadMemoryL(aMessage);
+ break;
+
+ case EDebugServWriteMemory:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServWriteMemory\n" );
+ WriteMemoryL(aMessage);
+ break;
+
+ case EDebugServSetBreak:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSetBreak\n" );
+ SetBreakL(aMessage);
+ break;
+
+ case EDebugServClearBreak:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServClearBreak\n" );
+ ClearBreakL(aMessage);
+ break;
+
+ case EDebugServModifyBreak:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServModifyBreak\n" );
+ ModifyBreakL(aMessage);
+ break;
+
+ case EDebugServModifyProcessBreak:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServModifyProcessBreak\n" );
+ ModifyProcessBreakL(aMessage);
+ break;
+
+ case EDebugServBreakInfo:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServBreakInfo\n" );
+ BreakInfoL(aMessage);
+ break;
+
+ case EDebugServReadRegisters:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServReadRegisters\n" );
+ ReadRegistersL(aMessage);
+ break;
+
+ case EDebugServWriteRegisters:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServWriteRegisters\n" );
+ WriteRegistersL(aMessage);
+ break;
+
+ case EDebugServGetEvent:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetEvent\n" );
+ GetEventL(aMessage);
+ break;
+
+ case EDebugServCancelGetEvent:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServCancelGetEvent\n" );
+ CancelGetEventL(aMessage);
+ break;
+
+ case EDebugServAttachExecutable:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServAttachExecutable\n" );
+ AttachProcessL(aMessage);
+ break;
+
+ case EDebugServDetachExecutable:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServDetachExecutable\n" );
+ DetachProcessL(aMessage);
+ break;
+
+ case EDebugServAttachAll:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServAttachAll\n" );
+ AttachAllL(aMessage);
+ break;
+
+ case EDebugServDetachAll:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServDetachAll\n" );
+ DetachAllL(aMessage);
+ break;
+
+ case EDebugServGetDebugFunctionalityBufSize:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetDebugFunctionalityBufSize\n" );
+ GetDebugFunctionalityBufSizeL(aMessage);
+ break;
+
+ case EDebugServGetDebugFunctionality:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetDebugFunctionality\n" );
+ GetDebugFunctionalityL(aMessage);
+ break;
+
+ case EDebugServSetEventAction:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSetEventAction\n" );
+ SetEventActionL(aMessage);
+ break;
+
+ case EDebugServGetList:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetList\n" );
+ GetListL(aMessage);
+ break;
+
+ case EDebugServStep:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServStep\n");
+ StepL(aMessage);
+ break;
+
+ case EDebugServSetProcessBreak:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServSetProcessBreak\n");
+ SetProcessBreakL(aMessage);
+ break;
+
+ case EDebugServProcessBreakInfo:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServProcessBreakInfo\n");
+ ProcessBreakInfoL(aMessage);
+ break;
+
+ case EDebugServKillProcess:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServKillProcess\n");
+ KillProcessL(aMessage);
+ break;
+
+#ifdef _DEBUG
+ case EDebugServMarkHeap:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServMarkHeap\n");
+ // all taken care of in HeapWatcher
+ aMessage.Complete(KErrNone);
+ break;
+
+ case EDebugServMarkEnd:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServMarkEnd\n");
+ // all taken care of in HeapWatcher
+ aMessage.Complete(KErrNone);
+ break;
+
+ case EDebugServFailAlloc:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServFailAlloc\n");
+ DoFailAlloc(aMessage);
+ break;
+#endif
+ case EDebugServReadCrashFlash:
+ ReadCrashLogL(aMessage);
+ break;
+ case EDebugServWriteCrashFlash:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServWriteCrashFlash\n");
+ WriteCrashConfigL(aMessage);
+ break;
+ case EDebugServEraseCrashFlash:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServEraseCrashFlash\n");
+ EraseCrashLogL(aMessage);
+ break;
+ case EDebugServEraseEntireCrashFlash:
+ LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServEraseEntireCrashFlash\n");
+ EraseEntireCrashLogL(aMessage);
+ break;
+ default:
+ LOG_MSG( "CSecuritySvrSession::ServiceL() Unknown request, calling User::Leave(KErrNotSupported);\n" );
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ //insert ending heap markers
+ HeapWatcher(aMessage.Function(), EFalse);
+
+ LOG_EXIT();
+ }
+
+#ifdef _DEBUG
+/**
+ Used to control heap failure in debug mode.
+ @param aMessage If aMessage.Int0 is non-zero then heap will be set to fail on that allocation.
+ If aMessage.Int0 is zero then the heap failure count is reset
+ */
+void CSecuritySvrSession::DoFailAlloc(const RMessage2& aMessage)
+ {
+ TInt count = aMessage.Int0();
+ if(count == 0)
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT(count);
+ }
+ aMessage.Complete(KErrNone);
+ }
+#endif
+
+/**
+Suspends execution of the specified thread.
+
+@param aMessage contains an integer representation of the target thread's
+ thread ID at offset 0.
+
+@leave KErrPermissionDenied if security check fails or KErrArgument if the
+ thread does not exist
+*/
+void CSecuritySvrSession::SuspendThreadL(const RMessage2& aMessage)
+ {
+
+ LOG_MSG( "CSecuritySvrSession::SuspendThreadL()\n" );
+
+ //get thread ID
+ TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+ //check attached
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ //security check passed so can perform actions
+ User::LeaveIfError(Server().iKernelDriver.SuspendThread(threadId));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Resumes execution of the specified thread.
+
+@param aMessage contains an integer representation of the target thread's
+ thread ID at offset 0.
+
+@leave KErrPermissionDenied if security check fails or KErrArgument if the
+ thread does not exist
+*/
+void CSecuritySvrSession::ResumeThreadL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::ResumeThreadL()\n" );
+
+ //get thread ID
+ TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ //check attached
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ //security check passed so can perform actions
+ TInt err = Server().iKernelDriver.ResumeThread(threadId);
+ aMessage.Complete(err);
+ }
+
+void CSecuritySvrSession::GetDebugFunctionalityBufSizeL(const RMessage2& aMessage)
+//
+// Retrieve size of functionality data buffer in bytes which must be allocated
+// by the client
+//
+ {
+ LOG_MSG( "CSecuritySvrSession::GetDebugFunctionalityBufSizeL()\n" );
+
+ TUint32 result = 0;
+ // Get Buffer size from the kernel driver
+ User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionalityBufSize(result));
+
+ TPtr8 stuff((TUint8*)&result,4, 4);
+
+ aMessage.WriteL(0,stuff);
+
+ aMessage.Complete(KErrNone);
+ }
+
+void CSecuritySvrSession::GetDebugFunctionalityL(const RMessage2& aMessage)
+//
+// Retrieve the functionality data and place it in a buffer
+// allocated by the client.
+//
+ {
+ LOG_MSG( "CSecuritySvrSession::GetDebugFunctionalityL()\n" );
+
+ TUint32 dfsize = 0;
+
+ // Get Buffer size from the kernel driver
+ User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionalityBufSize(dfsize));
+
+ // Allocate space for the functionality data
+ HBufC8* dftext = HBufC8::NewLC(dfsize);
+
+ const TPtr8& dfPtr = dftext->Des();
+
+ // Extract said data from the device driver
+ User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionality((TDes8&)dfPtr));
+
+ // Return data to client
+ aMessage.WriteL(0,dfPtr);
+
+ // Free buffer
+ CleanupStack::PopAndDestroy(dftext);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Reads memory from a specified thread using the passed parameters. The user
+should ensure that the TPtr8 that is passed in has size greater than or equal
+to the size of the memory that is trying to be read.
+
+@param aMessage The RMessage2 object should be constructed as follows:
+ * aMessage.Int0() is the thread ID of the target debug app
+ * aMessage.Ptr1() is a TMemoryInfo object which contains the following:
+ * the address of the memory to be read from the target debug thread
+ * the size of the memory block to be read from the target debug thread
+ * the access size to use
+ * the endianess to interpret the data as
+ * aMessage.Ptr2() is the address of the buffer in the debug agent thread
+ that the data from the target debug app should be written into
+
+@leave KErrPermissionDenied if client is not attached to the target
+ thread's process,
+ KErrNoMemory if memory could not be allocated,
+ KErrArgument if there are problems with the aMessage object,
+ KErrBadHandle if the thread represented by aMessage.Ptr0() is invalid,
+ an error value from CSecuritySvrSession::ValidateMemoryInfo if checking
+ the memory attributes failed,
+ or another of the system wide error codes
+*/
+void CSecuritySvrSession::ReadMemoryL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::ReadMemoryL()\n" );
+
+ //get debug app thread ID
+ TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ CheckAttachedL(threadId, aMessage, ETrue);
+
+ //create and initialise the memory info object
+ TMemoryInfo targetMemory;
+ TPtr8 targetMemoryPtr( (TUint8 *)&targetMemory, sizeof(TMemoryInfo) );
+
+ aMessage.ReadL(1,targetMemoryPtr);
+
+ //check memory info is acceptable
+ ValidateMemoryInfoL(threadId, targetMemory, ETrue);
+
+ RBuf8 data;
+ data.CreateL(targetMemory.iSize);
+ data.CleanupClosePushL();
+
+ //fill buffer with data from target debug thread
+ User::LeaveIfError(Server().iKernelDriver.ReadMemory(threadId, targetMemory.iAddress, targetMemory.iSize, data));
+
+ //attempt to write the data from the target debug thread back to the agent
+ aMessage.WriteL(2, data);
+
+ //delete temporary buffer
+ CleanupStack::PopAndDestroy(&data);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Writes memory to a specified thread using the passed parameters.
+
+@param aMessage The RMessage2 object should be constructed as follows:
+ * aMessage.Ptr0() is the thread ID of the target debug app
+ * aMessage.Ptr1() is a TMemoryInfo object which contains the following:
+ * the address of the memory to be written to the target debug thread
+ * the size of the memory block to be written to the target debug thread
+ * the access size to use
+ * the endianess to interpret the data as
+ * aMessage.Ptr2() is the address of the buffer in the debug agent thread
+ that the data to write to the target debug app should be read from
+
+@leave KErrPermissionDenied if client is not attached (actively) to the target
+ thread's process,
+ KErrNoMemory if memory could not be allocated,
+ KErrArgument if there are problems with the aMessage object,
+ KErrBadHandle if the thread represented by aMessage.Ptr0() is invalid,
+ an error value from CSecuritySvrSession::ValidateMemoryInfo if checking
+ the memory attributes failed,
+ or another of the system wide error codes
+*/
+void CSecuritySvrSession::WriteMemoryL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::WriteMemoryL()\n" );
+
+ //get debug app thread ID
+ TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ //create and initialise the memory info object
+ TMemoryInfo targetMemory;
+ TPtr8 targetMemoryPtr( (TUint8 *)&targetMemory, sizeof(TMemoryInfo) );
+
+ aMessage.ReadL(1,targetMemoryPtr);
+
+ //check memory info is acceptable
+ ValidateMemoryInfoL(threadId, targetMemory, EFalse);
+
+ //create temporary buffer and read data from client
+ RBuf8 data;
+ data.CreateL(targetMemory.iSize);
+ data.CleanupClosePushL();
+
+ aMessage.ReadL(2, data);
+
+ // what about telling the driver about endianess/access size?
+ User::LeaveIfError(Server().iKernelDriver.WriteMemory(threadId, targetMemory.iAddress, targetMemory.iSize, data));
+
+ //free temporary buffer
+ CleanupStack::PopAndDestroy(&data);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@internalTechnology
+
+Notes: This call is used to set a thread specific breakpoint. Its input arguments
+are the thread id, address and architecture type of the breakpoint. It returns success
+or failure, and if successful, it sets the TBreakId in the Debug Agent to the
+breakpoint id by which it can be referenced in future calls to ModifyBreak,ClearBreak and
+BreakInfo.
+
+@param aMessage.Ptr0() - aThreadId is thread id of the target debug process
+@param aMessage.Ptr1() - Address of a TBreakInfo in the Debug Agent
+@param aMessage.Ptr2() - Address of a TBreakId in the Debug Agent
+@leave KErrPermissionDenied if the security check fails.
+ KErrAlreadyExists if there is a breakpoint overlapping the desired address.
+ KErrNotSupported if the architecture type is unrecognised.
+ KErrNoMemory if there is no more memory to complete the operation.
+ KErrArgument if the breakpoint address alignment is unsuitable for the requested
+ breakpoint.
+ KErrOverflow if there are too many breakpoints set.
+*/
+void CSecuritySvrSession::SetBreakL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::SetBreakL!()\n" );
+
+ //get debug app thread ID
+ TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ //create and initialise the break info object
+ TBreakInfo breakInfo;
+ TPtr8 breakInfoPtr( (TUint8 *)&breakInfo, sizeof(TBreakInfo) );
+
+ aMessage.ReadL(1,breakInfoPtr);
+
+ LOG_MSG4( "CSecuritySvrSession::SetBreakL, threadId=0x%lx, addr=0x%x, mode=%d",
+ threadId.Id(), breakInfo.iAddress, breakInfo.iArchitectureMode);
+
+ //set break in target app
+ TBreakId breakId = 0;
+ User::LeaveIfError(Server().iKernelDriver.SetBreak(breakId, threadId, breakInfo.iAddress, breakInfo.iArchitectureMode));
+
+ //attempt to write the break id back to the debug agent
+ WriteDataL(aMessage, 2, &breakId, sizeof(breakId));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Clears a breakpoint previously set by a SetBreak() call.
+
+@param aMessage.Int0() - TBreakId of the breakpoint to be removed.
+*/
+void CSecuritySvrSession::ClearBreakL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::ClearBreakL()\n" );
+
+ const TInt breakId = aMessage.Int0();
+
+ // Check that the breakpoint exists
+ TUint64 objectId;
+ TUint32 address;
+ TArchitectureMode mode;
+ TBool threadSpecific = EFalse;
+
+ User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,objectId,address,mode,threadSpecific));
+
+ if(threadSpecific)
+ {
+ // Check that the debug agent is attached to the thread for which the
+ // breakpoint is currently set.
+ LOG_MSG4( "CSecuritySvrSession::ClearBreakL( brkId=%d), addr=0x%x, tId=0x%x",
+ breakId, address, I64LOW(objectId) );
+ CheckAttachedL(TThreadId(objectId), aMessage, EFalse);
+ }
+ else
+ {
+ // Check that the debug agent is attached to the process for which the
+ // breakpoint is currently set.
+ LOG_MSG4( "CSecuritySvrSession::ClearBreakL( brkId=%d), addr=0x%x, pId=0x%x",
+ breakId, address, I64LOW(objectId) );
+ CheckAttachedL(TProcessId(objectId), aMessage, EFalse);
+ }
+
+ // Finally clear the breakpoint
+ User::LeaveIfError(Server().iKernelDriver.ClearBreak(breakId));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@param aMessage.Int0() - Breakpoint Id of interest
+@param aMessage.Ptr1() - Address in Debug Agent to place threadId of the breakpoint
+@param aMessage.Ptr2() - Address in Debug Agent to place address of the breakpoint
+@param aMessage.Ptr3() - Address in Debug Agent to place the architecture mode of the breakpoint
+@leave Any error which may be returned by RSessionBase::SendReceive()
+*/
+void CSecuritySvrSession::BreakInfoL(const RMessage2& aMessage)
+ {
+ const TBreakId breakId = (TBreakId)aMessage.Int0();
+
+ TThreadId threadId;
+ TUint32 address;
+ TArchitectureMode mode;
+ TBool threadSpecific = ETrue;
+
+ TUint64 threadIdData;
+ User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,threadIdData,address,mode,threadSpecific));
+
+ if(!threadSpecific)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ threadId = TThreadId(threadIdData);
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ // return the threadId
+ WriteDataL(aMessage, 1, &threadId, sizeof(threadId));
+
+ // return the address
+ WriteDataL(aMessage, 2, &address, sizeof(address));
+
+ // return the mode
+ WriteDataL(aMessage, 3, &mode, sizeof(mode));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@internalTechnology
+
+Modify a previously set breakpoint.
+
+@param aMessage.Int0() - The breakpoint id of the breakpoint to modify
+@param aMessage.Ptr1() - The new Thread Id for the breakpoint
+@param aMessage.Int2() - The new virtual memory address for the breakpoint
+@param aMessage.Int3() - The new architecture mode for the breakpoint
+@return KErrNone if succesful. KErrPermissionDenied if the security check fails.
+ KErrAlreadyExists if there is a breakpoint overlapping the desired address.
+ KErrNotSupported if the architecture type is unrecognised.
+ KErrNoMemory if there is no more memory to complete the operation.
+ KErrArgument if the breakpoint address alignment is unsuitable for the requested
+ breakpoint.
+ KErrOverflow if there are too many breakpoints set.
+*/
+void CSecuritySvrSession::ModifyBreakL(const RMessage2& aMessage)
+ {
+ const TBreakId breakId = (TBreakId)aMessage.Int0();
+ const TThreadId threadId = ReadTThreadIdL(aMessage, 1);
+ const TUint32 address = aMessage.Int2();
+ const TArchitectureMode mode = (TArchitectureMode)aMessage.Int3();
+
+ // Get information on the breakpoint to check the security status
+ TUint64 checkThreadId;
+ TUint32 checkAddress;
+ TArchitectureMode checkMode;
+ TBool threadSpecific;
+
+ User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,checkThreadId,checkAddress,checkMode,threadSpecific));
+
+ LOG_MSG4( "CSecuritySvrSession::ModifyBreakL(brkId=%d) tId=0x%x, addr=0x%x",
+ breakId, I64LOW(threadId.Id()), address );
+
+ // Security check that the thread Id is associated with the debug agent
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(TThreadId(checkThreadId), aMessage, EFalse);
+
+ // now check that the thread Id which is being set is permitted
+ //check that the agent has attached to the target process
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ User::LeaveIfError(Server().iKernelDriver.ModifyBreak(breakId,threadId,address,mode));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@internalTechnology
+
+Notes: This call is used to set a process wide breakpoint. Its input arguments
+are the process id, address and architecture type of the breakpoint. It returns success
+or failure, and if successful, it sets the TBreakId in the Debug Agent to the
+breakpoint id by which it can be referenced in future calls to ModifyBreak,ClearBreak and
+BreakInfo.
+
+@param aMessage.Ptr0() - aProcessId is process id of the target debug process
+@param aMessage.Ptr1() - Address of a TBreakInfo in the Debug Agent
+@param aMessage.Ptr2() - Address of a TBreakId in the Debug Agent
+@leave KErrPermissionDenied if the security check fails.
+ KErrAlreadyExists if there is a breakpoint overlapping the desired address.
+ KErrNotSupported if the architecture type is unrecognised.
+ KErrNoMemory if there is no more memory to complete the operation.
+ KErrArgument if the breakpoint address alignment is unsuitable for the requested
+ breakpoint.
+ KErrOverflow if there are too many breakpoints set.
+*/
+void CSecuritySvrSession::SetProcessBreakL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::SetProcessBreakL()\n" );
+
+ //get debug app thread ID
+ TProcessId procId = ReadTProcessIdL(aMessage, 0);
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(procId, aMessage, EFalse);
+
+ //create and initialise the memory info object
+ TBreakInfo breakInfo;
+ TPtr8 breakInfoPtr( (TUint8 *)&breakInfo, sizeof(TBreakInfo) );
+
+ aMessage.ReadL(1,breakInfoPtr);
+
+ LOG_MSG4( "CSecuritySvrSession::SetProcessBreakL pId=0x%x, addr=0x%x, mode=%d ",
+ I64LOW(procId.Id()), breakInfo.iAddress, breakInfo.iArchitectureMode );
+
+ //set break in target app
+ TBreakId breakId = 0;
+ User::LeaveIfError(Server().iKernelDriver.SetProcessBreak(breakId, procId, breakInfo.iAddress, breakInfo.iArchitectureMode));
+
+ //attempt to write the break id back to the debug agent
+ WriteDataL(aMessage, 2, &breakId, sizeof(breakId));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@internalTechnology
+
+Modify a previously set process breakpoint.
+
+@param aMessage.Int0() - The breakpoint id of the breakpoint to modify
+@param aMessage.Ptr1() - The new Process Id for the breakpoint
+@param aMessage.Int2() - The new virtual memory address for the breakpoint
+@param aMessage.Int3() - The new architecture mode for the breakpoint
+@return KErrNone if succesful. KErrPermissionDenied if the security check fails.
+ KErrAlreadyExists if there is a breakpoint overlapping the desired address.
+ KErrNotSupported if the architecture type is unrecognised.
+ KErrNoMemory if there is no more memory to complete the operation.
+ KErrArgument if the breakpoint address alignment is unsuitable for the requested
+ breakpoint.
+ KErrOverflow if there are too many breakpoints set.
+*/
+void CSecuritySvrSession::ModifyProcessBreakL(const RMessage2& aMessage)
+ {
+ const TBreakId breakId = (TBreakId)aMessage.Int0();
+ const TProcessId processId = ReadTProcessIdL(aMessage, 1);
+ const TUint32 address = aMessage.Int2();
+ const TArchitectureMode mode = (TArchitectureMode)aMessage.Int3();
+
+ // Get information on the breakpoint to check the security status
+ TUint64 checkProcessId;
+ TUint32 checkAddress;
+ TArchitectureMode checkMode;
+ TBool threadSpecific;
+
+ User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,checkProcessId,checkAddress,checkMode,threadSpecific));
+
+ LOG_MSG4( "CSecuritySvrSession::ModifyProcessBreakL(brkId=%d) pId=0x%x, addr=0x%x",
+ breakId, I64LOW(processId.Id()), address );
+
+
+ // Security check that the process Id is associated with the debug agent
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(TProcessId(checkProcessId), aMessage, EFalse);
+
+ // now check that the process Id which is being set is permitted
+ //check that the agent has attached to the target process
+ CheckAttachedL(processId, aMessage, EFalse);
+
+ User::LeaveIfError(Server().iKernelDriver.ModifyProcessBreak(breakId,processId,address,mode));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@param aMessage.Int0() - Breakpoint Id of interest
+@param aMessage.Ptr1() - Address in Debug Agent to place process Id of the breakpoint
+@param aMessage.Ptr2() - Address in Debug Agent to place address of the breakpoint
+@param aMessage.Ptr3() - Address in Debug Agent to place the architecture mode of the breakpoint
+@leave Any error which may be returned by RSessionBase::SendReceive()
+*/
+void CSecuritySvrSession::ProcessBreakInfoL(const RMessage2& aMessage)
+ {
+ const TBreakId breakId = (TBreakId)aMessage.Int0();
+
+ TProcessId procId;
+ TUint32 address;
+ TArchitectureMode mode;
+ TBool threadSpecific;
+
+ TUint64 procIdData;
+ User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,procIdData,address,mode,threadSpecific));
+ if(threadSpecific)
+ {
+ User::Leave(KErrNotFound);
+ }
+ procId = TProcessId(procIdData);
+
+ //check that the agent has attached to the target process
+ CheckAttachedL(procId, aMessage, EFalse);
+
+ // return the processId
+ WriteDataL(aMessage, 1, &procId, sizeof(procId));
+
+ // return the address
+ WriteDataL(aMessage, 2, &address, sizeof(address));
+
+ // return the mode
+ WriteDataL(aMessage, 3, &mode, sizeof(mode));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Read register values.
+
+@param aMessage should contain:
+ * at offset 0 a pointer to the thread ID of the target thread
+ * at offset 1 a descriptor representing an array of TRegisterInfo
+ register IDs
+ * at offset 2 a descriptor representing an array into which TRegister
+ register values will be written
+ * at offset 3 a descriptor representing an array into which TUint8
+ register flags will be written
+
+@leave KErrArgument if the max length of the array at offset 1 is not a
+ multiple of sizeof(TRegisterInfo), if the max length of the array
+ at offset 2 is not a multiple of sizeof(TRegister), if the max
+ length of the array at offset 3 is not a multiple of sizeof(TUint8), if
+ any of the descriptors have max length of 0, or if the three
+ descriptors do not represent the same number of registers,
+ KErrNoMemory if there is insufficient memory,
+ KErrDied, if the thread with thread ID aThreadId is dead
+*/
+void CSecuritySvrSession::ReadRegistersL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::ReadRegistersL()\n" );
+
+ const TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ //check the agent is attached to the thread
+ CheckAttachedL(threadId, aMessage, ETrue);
+
+ //number of registers being requested
+ TUint32 numberOfRegisters;
+
+ //check length of descriptors is acceptable
+ ValidateRegisterBuffersL(aMessage, numberOfRegisters);
+
+ // Passed data will be saved in this descriptor.
+ RBuf8 ids;
+ ids.CreateL(numberOfRegisters * sizeof(TRegisterInfo));
+ // Do the right cleanup if anything subsequently goes wrong
+ ids.CleanupClosePushL();
+
+ //read the data from the client thread
+ aMessage.ReadL(1, ids);
+
+ //create buffer to fill with data from target debug thread
+ HBufC8 *data = HBufC8::NewLC(aMessage.GetDesMaxLength(2));
+ TPtr8 values(data->Des());
+
+ HBufC8 *flagsData = HBufC8::NewLC(numberOfRegisters * sizeof(TUint8));
+ TPtr8 flags(flagsData->Des());
+
+ //get register info and return relevant parts back to agent
+ User::LeaveIfError(Server().iKernelDriver.ReadRegisters(threadId, ids, values, flags));
+ aMessage.WriteL(2, values);
+ aMessage.WriteL(3, flags);
+
+ //delete temporary buffers and return status
+ CleanupStack::PopAndDestroy(flagsData);
+ CleanupStack::PopAndDestroy(data);
+ CleanupStack::PopAndDestroy(&ids);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Write register values.
+
+@param aMessage should contain:
+ * at offset 0 a pointer to the thread ID of the target thread
+ * at offset 1 a descriptor representing an array of TRegisterInfo
+ register IDs
+ * at offset 2 a descriptor representing an array of TRegister register
+ values
+ * at offset 3 a descriptor representing an array into which TUint8
+ register flags will be written
+
+@leave KErrArgument if the max length of the array at offset 1 is not a
+ multiple of sizeof(TRegisterInfo), if the max length of the array
+ at offset 2 is not a multiple of sizeof(TRegister), if the max
+ length of the array at offset 3 is not a multiple of sizeof(TUint8), if
+ any of the descriptors have max length of 0, or if the three
+ descriptors do not represent the same number of registers,
+ KErrNoMemory if there is insufficient memory,
+ KErrDied, if the thread with thread ID aThreadId is dead
+*/
+void CSecuritySvrSession::WriteRegistersL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::WriteRegistersL()\n" );
+
+ const TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ //number of registers attempting to set
+ TUint32 numberOfRegisters;
+
+ //check length of descriptors is acceptable
+ ValidateRegisterBuffersL(aMessage, numberOfRegisters);
+
+ // Passed register ids will be saved in this descriptor.
+ RBuf8 ids;
+
+ //allocate buffer
+ ids.CreateL(numberOfRegisters * sizeof(TRegisterInfo));
+
+ // Do the right cleanup if anything subsequently goes wrong
+ ids.CleanupClosePushL();
+
+ //read the data from the client thread
+ aMessage.ReadL(1, ids);
+
+ // Passed register values will be saved in this descriptor.
+ RBuf8 values;
+
+ //allocate buffer
+ values.CreateL(aMessage.GetDesMaxLength(2));
+ // Do the right cleanup if anything subsequently goes wrong
+ values.CleanupClosePushL();
+ //read the data from the client thread
+ aMessage.ReadL(2,values);
+
+ HBufC8 *flagsData = HBufC8::NewLC(numberOfRegisters*sizeof(TUint8));
+ TPtr8 flags(flagsData->Des());
+
+ //get register info and return relevant parts back to agent
+ User::LeaveIfError(Server().iKernelDriver.WriteRegisters(threadId, ids, values, flags));
+
+ //write flags data back
+ aMessage.WriteL(3, flags);
+
+ CleanupStack::PopAndDestroy(flagsData);
+ CleanupStack::PopAndDestroy(&values);
+ CleanupStack::PopAndDestroy(&ids);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Processes an attach request from a debug agent. Gets the target debug
+processes' original FileName as an argument. The method sets completion
+status of the aMessage argument to KErrNone if successfully attached and to
+another of the system wide error codes if there were problems.
+
+@param aMessage contains:
+ * a boolean at offset 0 which indicates whether the agent wishes to
+ attach passively
+ * a buffer at offset 1 which contains the FileName
+ of the target debug process.
+*/
+void CSecuritySvrSession::AttachProcessL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::AttachProcessL()\n" );
+
+ const TBool passive = aMessage.Int0();
+
+ TInt deslen = aMessage.GetDesLengthL(1);
+
+ // Passed data will be saved in this descriptor.
+ RBuf processName;
+
+ // Max length set to the value of "deslen", but current length is zero
+ processName.CreateL(deslen);
+
+ // Do the right cleanup if anything subsequently goes wrong
+ processName.CleanupClosePushL();
+
+ // Copy the client's descriptor data into our buffer.
+ aMessage.ReadL(1,processName);
+
+ //
+ // Security Check
+ //
+ // It is not permitted to debug the debug security server!
+ //
+ // get the secure id of the executable
+ TUid secureId(TUid::Null());
+ GetSecureIdL(processName, secureId);
+ if (KUidDebugSecurityServer.iUid == secureId.iUid)
+ {
+ // The debug agent has requested to debug the Debug Security Server
+ // This is either an error, or an attempt to breach security. We
+ // therefore refuse to agree to this request, and return KErrPermissionDenied
+ LOG_MSG("Debug Agent attempted to debug the Debug Security Server");
+ User::Leave(KErrPermissionDenied);
+ }
+
+ // Check the OEM Debug token capabilities
+ GetDebugAgentOEMTokenCapsL();
+
+ // Get the Security info via rlibrary::getinfo
+ RLibrary::TInfo info;
+ TPckg<RLibrary::TInfo> infoBuf(info);
+
+ TInt err = RLibrary::GetInfo(processName, infoBuf);
+ if (err != KErrNone)
+ {
+ LOG_MSG2("Cannot parse the target executable header, err=%d", err);
+ // Could not read the header for this executable :-(
+ CleanupStack::PopAndDestroy(&processName);
+ aMessage.Complete(err);
+ return;
+ }
+
+ // Special case for AllFiles - OEM Debug tokens MUST have
+ // AllFiles, as this is what allows them to read contents
+ // of other executables.
+ TBool checkDebuggable = ETrue;
+
+ // Does an OEM Debug Token permit debug where it would normally not be
+ // permitted?
+ if ( Server().OEMTokenPermitsDebugL(iOEMDebugCapabilities, info.iSecurityInfo.iCaps) )
+ {
+ // OEM Debug token is valid and has sufficient capabilities
+ LOG_MSG("CSecuritySvrSession::AttachProcessL() - Debug Agent has sufficient capabilites based on OEM Debug Token");
+
+ checkDebuggable = EFalse;
+ }
+
+ if (checkDebuggable)
+ {
+ // OEM Debug token (if any), does not confer sufficient capabilities to
+ // debug the specified target executable. Therefore debugging can only
+ // be permitted if the target executable itself has been built as 'Debuggable'
+ LOG_MSG("CSecuritySvrSession::AttachProcessL() - Debug Agent has insufficient capabilites based on OEM Debug Token");
+
+ IsDebuggableL(processName);
+ }
+
+ User::LeaveIfError(Server().AttachProcessL(processName, iDebugAgentProcessId, passive));
+
+ // Inform the kernel driver about the attachment, so that it
+ // can track per-agent data about the process.
+ RBuf8 processName8;
+
+ processName8.CreateL(deslen);
+
+ processName8.CleanupClosePushL();
+
+ processName8.Copy(processName);
+
+ User::LeaveIfError(Server().iKernelDriver.AttachProcess(processName8, iDebugAgentProcessId.Id()));
+
+ // Create an Active Object to handle asynchronous calls to GetEvent
+ CSecuritySvrAsync* handler = CSecuritySvrAsync::NewL(this,processName8,iDebugAgentProcessId);
+
+ err = iAsyncHandlers.Insert(handler,0);
+ if (err != KErrNone)
+ {
+ // If we don't have an asynchronous handler, we should detach
+ // the driver as well.
+ Server().iKernelDriver.DetachProcess(processName8,iDebugAgentProcessId.Id());
+ Server().DetachProcess(processName, iDebugAgentProcessId);
+ // The DSS should NEVER panic itself. If the above calls fail, so be it we will attempt to limp on
+ }
+
+ User::LeaveIfError(err);
+
+ CleanupStack::PopAndDestroy(&processName8);
+
+ CleanupStack::PopAndDestroy(&processName);
+
+ aMessage.Complete(KErrNone);
+ }
+
+
+/**
+Processes an attach request from a debug agent from all processes.
+The method sets completion status of the aMessage argument to KErrNone
+if successfully attached and to another of the system wide error codes
+if there were problems.
+
+@param aMessage contains no data
+*/
+void CSecuritySvrSession::AttachAllL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::AttachAllL()\n" );
+
+
+ // Run the OEM Debug token, if run ok then sets iOEMDebugCapabilities
+ GetDebugAgentOEMTokenCapsL();
+
+ // Debug token must have All caps to use AttachToAll
+ TCapabilitySet allCaps;
+ allCaps.SetAllSupported();
+ if (!Server().OEMTokenPermitsDebugL(iOEMDebugCapabilities, allCaps))
+ {
+ LOG_MSG("Client's OEM token doesn't have capability ALL required for AttachAll()");
+ User::Leave(KErrPermissionDenied);
+ }
+
+
+ User::LeaveIfError(Server().AttachProcessL(_L("*"), iDebugAgentProcessId, EFalse));
+
+ TBuf8<1> KStar8=_L8("*");
+
+ User::LeaveIfError(Server().iKernelDriver.AttachProcess(KStar8, iDebugAgentProcessId.Id()));
+
+ // Create an Active Object to handle asynchronous calls to GetAllEvent
+ CSecuritySvrAsync* handler = CSecuritySvrAsync::NewL(this,KStar8,iDebugAgentProcessId);
+ TInt err = iAsyncHandlers.Insert(handler,0);
+ if (err != KErrNone)
+ {
+ // If we don't have an asynchronous handler, we should detach
+ // the driver as well.
+ Server().iKernelDriver.DetachProcess(KStar8,iDebugAgentProcessId.Id());
+ Server().DetachProcess(_L("*"), iDebugAgentProcessId);
+ }
+
+ User::LeaveIfError(err);
+
+ aMessage.Complete(KErrNone);
+ }
+
+
+/**
+Reads the OEM Debug Token associated with the debug agent if any. The OEM Debug Token
+allows the Debug Agent to debug certain executables which have not been built as
+'Debuggable'.
+
+This works as follows: The OEM Debug Token is an executable with a special name
+of the form "OEMDebug_<DA_SID>.exe" where <DA_SID> is the Secure ID of the Debug Agent
+in hexadecimal. For example: "OEMDebug_F123ABCD.exe" would be a valid name. This token executable
+must be signed with 'AllFiles' + X, where X is the set of PlatSec capabilities that are
+possessed by the target executable to be debugged.
+
+This function reads the capabilities possessed by the token by creating a process based
+on the executable, and reading the TSecurityInfo associated with the process. This ensures
+that the loader has validated the token has not been tampered with and that the security
+information is valid.
+
+The security information is then stored for future use as member data in iOEMDebugCapabilities.
+
+Leaves if there is an error, otherwise simply fills in the capabilities
+in iOEMDebugCapabilities.
+
+It is not an error for the OEM Debug token not to exist. In this case, the function simply returns.
+*/
+void CSecuritySvrSession::GetDebugAgentOEMTokenCapsL(void)
+ {
+ if (iOEMDebugCapabilities.HasCapability(ECapabilityAllFiles))
+ {
+ // Then we've already read the caps - wasteful to read them again
+ return;
+ }
+
+ // Obtain the security info about the debug agent process
+ //get the debug agent's process
+ RProcess debugAgentProcess;
+
+ CleanupClosePushL(debugAgentProcess);
+
+ debugAgentProcess.Open(iDebugAgentProcessId);
+
+ // We have now obtained a process handle based on the token executable, so we can check its security properties.
+ TSecurityInfo secInfo(debugAgentProcess);
+
+ // Compute the name of the OEM debug token based on the SID of the debug agent
+ _LIT(KDSSOEMDebugTokenPrefix,"OEMDebug_");
+ _LIT(KDSSOEMDebugTokenAppendFmt,"%08X.exe");
+
+ RBuf agentTokenName;
+ agentTokenName.CreateL(KDSSOEMDebugTokenPrefix().Size()+8+1); // allow space for SID+null terminator
+ agentTokenName.CleanupClosePushL();
+
+ agentTokenName.SetLength(0);
+
+ // Add OEMDebug_
+ agentTokenName.Append(KDSSOEMDebugTokenPrefix());
+
+ // Add debug agent Secure ID
+ agentTokenName.AppendFormat(KDSSOEMDebugTokenAppendFmt,secInfo.iSecureId.iId);
+
+ // just log the token name for the moment.
+ RBuf8 agentTokenName8;
+
+ agentTokenName8.CreateL(agentTokenName.Length()+1);
+
+ agentTokenName8.CleanupClosePushL();
+
+ agentTokenName8.Copy(agentTokenName);
+
+ agentTokenName8.Append(TChar(0));
+
+ LOG_MSG2("CSecuritySvrSession::GetDebugAgentOEMTokenCapsL() - OEM Debug Token Name is %s",agentTokenName8.Ptr());
+
+ // Cleanup
+ CleanupStack::PopAndDestroy(&agentTokenName8);
+
+ // Now locate and start the executable...
+ RProcess agentToken;
+ TInt err = agentToken.Create(agentTokenName, KNullDesC);
+ if (KErrNone != err)
+ {
+ // Failed to create a process based on the token, just give up
+ LOG_MSG2("CSecuritySvrSession::GetDebugAgentOEMTokenCapsL() - Could not create process based on token due to err 0x%8x\n",err);
+
+ // Cleanup remaining items from the stack
+ CleanupStack::PopAndDestroy(&agentTokenName);
+
+ CleanupStack::PopAndDestroy(&debugAgentProcess);
+ return;
+ }
+
+ // Synchronise with the process to make sure it hasn't died straight away
+ TRequestStatus stat;
+ agentToken.Rendezvous(stat);
+ if (stat != KRequestPending)
+ {
+ // logon failed - agentToken is not yet running, so cannot have terminated
+ agentToken.Kill(0); // Abort startup
+ }
+
+ // store the OEM Debug Token security data
+ TSecurityInfo agentSecInfo(agentToken);
+
+ // Note capabilities for future use
+ iOEMDebugCapabilities=agentSecInfo.iCaps;
+
+ // resume the token. It _should_ just exit, but we don't really care.
+ agentToken.Resume();
+
+ // Wait to synchronise with agentToken - if it dies in the meantime, it
+ // also gets completed
+ User::WaitForRequest(stat);
+
+ // Just close the handle to it again.
+ agentToken.Close();
+
+ // Cleanup remaining items from the stack
+ CleanupStack::PopAndDestroy(&agentTokenName);
+
+ CleanupStack::PopAndDestroy(&debugAgentProcess);
+
+ }
+
+/**
+ Checks whether the file passed in as aExecutable is XIP or not
+
+ @param aExecutable file to check
+ @return ETrue if the file is XIP, EFalse otherwise
+ */
+TBool CSecuritySvrSession::IsExecutableXipL(RFile& aExecutable)
+ {
+ TUint atts;
+ User::LeaveIfError(aExecutable.Att(atts));
+
+ return atts & KEntryAttXIP;
+ }
+
+/**
+ Gets access to the symbian crash partition for crash access operation.
+ */
+void CSecuritySvrSession::ConnectCrashPartitionL (void)
+ {
+ LOG_MSG("CSecuritySvrSession::ConnectCrashPartitionL()");
+
+ TBool changed;
+ TInt error = KErrNone;
+ TInt i=0;
+
+ //Intialising to EFalse
+ iCrashConnected = EFalse;
+
+ TPckg<TLocalDriveCapsV2> capsBuf(iCaps);
+
+ //check for the symbian crash partition
+ for (i=0; i<KMaxLocalDrives; i++)
+ {
+ error = iLocalDrive.Connect (i, changed);
+ if ( error == KErrNone)
+ {
+ error = iLocalDrive.Caps(capsBuf);
+ if ( error != KErrNone)
+ {
+ //continue if not found
+ continue;
+ }
+ if ( iCaps.iPartitionType == (TUint16)KPartitionTypeSymbianCrashLog)
+ {
+ LOG_MSG2("Found Symbian crash log partition on drive: %d",i);
+ iCrashConnected = ETrue;
+ break;
+ }
+ }
+ }
+ if ( i == KMaxLocalDrives)
+ {
+ LOG_MSG("No crash log partition found with valid crash log signature found. Exiting...");
+ User::Leave (KErrNotFound);
+ }
+
+ // Nand Flash not currently supported.
+ if (iCaps.iType == EMediaNANDFlash)
+ {
+ LOG_MSG( "CSecuritySvrSession::ConnectCrashPartitionL() Nand Flash not currently supported\n" );
+ User::Leave (KErrNotSupported);
+ }
+ }
+/** Checks that aHeaderData contains enough data to cast it to the
+ appropriate header type.
+
+ @param aHeaderData buffer containing header data read from a file
+ @param aXip boolean indicating whether the header data is for an XIP image
+
+ @return ETrue if enough data in buffer, EFalse otherwise
+ */
+TBool CSecuritySvrSession::CheckSufficientData(const TDesC8& aHeaderData, const TBool aXip) const
+ {
+ TUint minimumHeaderSize = aXip ? sizeof(TRomImageHeader) : sizeof(E32ImageHeaderV);
+ return (aHeaderData.Length() >= minimumHeaderSize);
+ }
+
+/**
+ Opens a file handle to aFileName using aFileHandle
+ @param aFileName file to open handle to
+ @param aFs file system to use to open the handle
+ @param aFileHandle file handle to open
+
+ @leave one of the system wide error codes
+ */
+void CSecuritySvrSession::OpenFileHandleL(const TDesC& aFileName, RFs& aFs, RFile& aFileHandle)
+ {
+ TInt err = aFileHandle.Open(aFs, aFileName, EFileRead | EFileShareReadersOnly);
+ if (err != KErrNone)
+ {
+ // Could not open the file for reading
+ LOG_MSG("CSecuritySvrSession::OpenFileHandleL - Failed to open executable\n");
+
+ User::Leave(err);
+ }
+ }
+
+/**
+ Checks whether an executable has the debug bit set
+
+ @param aHeaderData buffer containing the header of the executable
+ @param aXip indication of whether the executable is XIP or not
+
+ @return ETrue if debug bit is set, EFalse otherwise
+ */
+TBool CSecuritySvrSession::IsDebugBitSet(const TDesC8& aHeaderData, const TBool aXip)
+ {
+ if(!CheckSufficientData(aHeaderData, aXip))
+ {
+ return EFalse;
+ }
+
+ if (aXip)
+ {
+ TRomImageHeader* hdr = (TRomImageHeader*)aHeaderData.Ptr();
+ return (hdr->iFlags & KRomImageDebuggable);
+ }
+ else
+ {
+ // it is an epoc32 image
+ E32ImageHeaderV* hdr = (E32ImageHeaderV*)aHeaderData.Ptr();
+ return (hdr->iFlags & KImageDebuggable);
+ }
+ }
+
+/**
+Determines whether a particular executable is marked as 'debuggable'
+
+Notes:
+This function is currently hard coded to understand the format of e32 and
+TRomImage file headers. Ideally this will be replaced by a call to RLibrary::GetInfo
+which can return the 'debuggable' information. Unfortunately, this call currently
+does not provide the information for XIP executables :-(
+
+@leave KErrPermissionDenied if the debug bit is not set, or one of the other
+system wide error codes
+*/
+void CSecuritySvrSession::IsDebuggableL(const TDesC& aFileName)
+ {
+#ifndef IGNORE_DEBUGGABLE_BIT
+
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ RFile targetExe;
+ OpenFileHandleL(aFileName, fs, targetExe);
+ CleanupClosePushL(targetExe);
+
+ // Read in the entire header
+ RBuf8 e32HdrBuf;
+ e32HdrBuf.CreateL(RLibrary::KRequiredImageHeaderSize);
+ e32HdrBuf.CleanupClosePushL();
+
+ // Read the entire header as far as possible
+ TInt err = targetExe.Read(e32HdrBuf);
+ if (err != KErrNone)
+ {
+ // Could not read the file
+ LOG_MSG("CSecuritySvrSession::IsDebuggableL - Failed to read executable\n");
+
+ User::Leave(err);
+ }
+
+ if(!CheckSufficientData(e32HdrBuf, IsExecutableXipL(targetExe)))
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ if(! IsDebugBitSet(e32HdrBuf, IsExecutableXipL(targetExe)))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+ CleanupStack::PopAndDestroy(3, &fs);
+
+#else
+ LOG_MSG("CSecuritySvrSession::IsDebuggableL() Debuggable bit temporarily ignored!!!");
+#endif
+ }
+
+/**
+Processes a detach request from a debug agent. Gets the target debug
+processes' original FileName as an argument. The method sets completion
+status of the aMessage argument to KErrNone if successfully detached and to
+another of the system wide error codes if there were problems.
+
+@param aMessage contains:
+ * a buffer at offset 0 which contains the FileName
+ of the target debug process.
+*/
+void CSecuritySvrSession::DetachProcessL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::DetachProcessL()\n" );
+
+ TInt deslen = aMessage.GetDesLengthL(0);
+ // Passed data will be saved in this descriptor.
+ RBuf processName;
+
+ // Max length set to the value of "deslen", but current length is zero
+ processName.CreateL(deslen);
+
+ // Do the right cleanup if anything subsequently goes wrong
+ processName.CleanupClosePushL();
+
+ // Copy the client's descriptor data into our buffer.
+ aMessage.ReadL(0,processName);
+
+ User::LeaveIfError(Server().DetachProcess(processName, iDebugAgentProcessId));
+
+ // Inform the kernel driver about the detachment, so that
+ // it can stop tracking per-agent data for the debugged process.
+ RBuf8 processName8;
+
+ processName8.CreateL(deslen);
+
+ processName8.CleanupClosePushL();
+
+ processName8.Copy(processName);
+
+ // Remove the Asynchronous Object associated with this process
+ for(TInt i=0; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 0)
+ {
+ delete iAsyncHandlers[i];
+ iAsyncHandlers.Remove(i);
+
+ break;
+ }
+ }
+
+ // Inform the driver that we are no longer attached to this process
+ User::LeaveIfError(Server().iKernelDriver.DetachProcess(processName8,iDebugAgentProcessId.Id()));
+
+ CleanupStack::PopAndDestroy(&processName8);
+ CleanupStack::PopAndDestroy(&processName);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+Processes a DetachAll request from a debug agent.
+The method sets completion status of the aMessage argument to
+KErrNone if successfully detached and to
+another of the system wide error codes if there were problems.
+
+@param aMessage contains:
+ * a buffer at offset 0 which contains the FileName
+ of the target debug process.
+*/
+void CSecuritySvrSession::DetachAllL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::DetachAllL()" );
+
+ User::LeaveIfError(Server().DetachProcess(_L("*"), iDebugAgentProcessId));
+
+ TBuf8<1> KStar8=_L8("*");
+
+ TBool found = EFalse;
+
+ // Remove the Asynchronous Object associated with the AttachAll, not the rest
+ for(TInt i=0; i<iAsyncHandlers.Count(); i++)
+ {
+ if (iAsyncHandlers[i]->ProcessName().Compare(KStar8) == 0)
+ {
+ delete iAsyncHandlers[i];
+ iAsyncHandlers.Remove(i);
+ User::LeaveIfError(Server().iKernelDriver.DetachProcess(KStar8,iDebugAgentProcessId.Id()));
+ found = ETrue;
+ break;
+ }
+ }
+
+ if( !found )
+ {
+ LOG_MSG2( "CSecuritySvrSession::DetachAllL() : Did not find the asynch handler for agent 0x%lx",
+ iDebugAgentProcessId.Id() );
+ User::Leave(KErrNotFound);
+ }
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+@param aMessage The RMessage2 object is expected to contain:
+ * aMessage.Int0() - TDes8 Containing the process name.
+ * aMessage.Int1() - Address of TPtr8 containing TEventInfo
+
+*/
+void CSecuritySvrSession::GetEventL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::GetEventL()\n" );
+
+ // Local descriptor to contain target process name
+ TInt deslen = aMessage.GetDesLengthL(0);
+
+ RBuf processName;
+
+ processName.CreateL(deslen);
+
+ processName.CleanupClosePushL();
+
+ // Read the target process name into processName
+ aMessage.ReadL(0,processName);
+
+ // Check if debug agent is attached to process
+ if(!Server().CheckAttachedProcess(processName, aMessage, EFalse))
+ {
+ LOG_MSG("CSecuritySvrSession::GetEventL() - Not attached to this process\n");
+
+ // Debug Agent is not attached at all to the requested process
+ User::Leave(KErrPermissionDenied);
+ }
+
+ // Identify which process is being debugged, so that
+ // we can locate the appropriate active object handler.
+ RBuf8 processName8;
+
+ processName8.CreateL(processName.Length());
+
+ processName8.CleanupClosePushL();
+
+ processName8.Copy(processName);
+
+ // Find the Asynchronous Object associated with this process,
+ // as it is permissible to have an outstanding GetEvent call
+ // for each attached process.
+ TBool foundHandler = EFalse;
+ for(TInt i=0; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 0)
+ {
+ iAsyncHandlers[i]->GetEvent(aMessage);
+ foundHandler = ETrue;
+ break;
+ }
+ }
+
+ if (foundHandler == EFalse)
+ {
+ // could not find an async handler object. Report the problem.
+ LOG_MSG("CSecuritySvrSessionL - Could not find a handler object\n");
+ User::Leave(KErrNotFound);
+ }
+
+ // Actually make the driver call, passing in the agent Id
+ // so that the driver knows which per-agent event queue
+ // to interrogate to retrieve the latest event.
+ CleanupStack::PopAndDestroy(&processName8);
+ CleanupStack::PopAndDestroy(&processName);
+ }
+
+/**
+Cancels a pre-issued GetEvent call for a specific debugged process.
+
+@param aMessage.Int0() - TDes8 containing aProcessName
+*/
+void CSecuritySvrSession::CancelGetEventL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::CancelGetEventL()\n" );
+
+ // Local descriptor to contain target process name
+ TInt deslen = aMessage.GetDesLengthL(0);
+
+ RBuf processName;
+
+ processName.CreateL(deslen);
+
+ processName.CleanupClosePushL();
+
+ // Read the target process name into processName
+ aMessage.ReadL(0,processName,0);
+
+ // Debug Agent is not an active debugger. Check if the DA is passively attached
+ if(!Server().CheckAttachedProcess(processName, aMessage, EFalse))
+ {
+ // Debug Agent is not attached at all to the requested process
+ User::Leave(KErrPermissionDenied);
+ }
+
+ // Identify the appropriate active object associate
+ // with this process.
+ RBuf8 processName8;
+
+ processName8.CreateL(processName.Length());
+
+ processName8.CleanupClosePushL();
+
+ processName8.Copy(processName);
+
+ // Find the Asynchronous Object associated with this process
+ TBool foundHandler = EFalse;
+ for(TInt i=0; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 0)
+ {
+
+ // Found the AO handler, so cancel the outstanding getevent call.
+ iAsyncHandlers[i]->Cancel();
+ foundHandler = ETrue;
+ break;
+ }
+ }
+
+ if(!foundHandler)
+ {
+ // We could not found a handler, so report the problem to the debug agent
+ User::Leave(KErrNotFound);
+ }
+
+ //do cleanup
+ CleanupStack::PopAndDestroy(&processName8);
+ CleanupStack::PopAndDestroy(&processName);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/*
+ Purpose: Sets the required event action to be taken for a specific
+ process and event combination
+
+@param aMessage The RMessage2 object is expected to contain:
+ * aMessage.Int0() - TDes8 Containing the process name.
+ * aMessage.Int1() - TEventType
+ * aMessage.Int2() - TKernelEventAction
+ *
+*/
+void CSecuritySvrSession::SetEventActionL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::SetEventActionL()\n" );
+
+ // Local descriptor to contain target process name
+ TInt deslen = aMessage.GetDesLengthL(0);
+
+ RBuf processName;
+
+ processName.CreateL(deslen);
+
+ processName.CleanupClosePushL();
+
+ // Read the target process name into processName
+ aMessage.ReadL(0,processName);
+
+ //check that the agent has attached to the target process
+ if(!Server().CheckAttachedProcess(processName, aMessage, EFalse))
+ {
+ // Debug Agent is not attached at all to the requested process
+ User::Leave(KErrPermissionDenied);
+ }
+
+ // Extract and validate the arguments from aMessage
+ TUint32 event = aMessage.Int1();
+ if (event >= EEventsLast)
+ {
+ // Supplied event Id was not recognised
+ User::Leave(KErrArgument);
+ }
+
+ TUint32 action = aMessage.Int2();
+ if(action >= EActionLast)
+ {
+ // Supplied event action was not recognised
+ User::Leave(KErrArgument);
+ }
+
+ RBuf8 processName8;
+
+ processName8.CreateL(processName.Length());
+
+ processName8.CleanupClosePushL();
+
+ processName8.Copy(processName);
+
+ // Make the call to the device driver
+ TInt err = Server().iKernelDriver.SetEventAction(processName8, \
+ (TEventType)event,\
+ (TKernelEventAction)action,\
+ iDebugAgentProcessId.Id());
+
+ User::LeaveIfError(err);
+
+ CleanupStack::PopAndDestroy(&processName8);
+ CleanupStack::PopAndDestroy(&processName);
+
+ aMessage.Complete(KErrNone);
+}
+
+/**
+Purpose: Single-step a thread for a specified number of instructions
+
+@param aMessage.Ptr0() - Thread Id of the thread to be stepped
+@param aMessage.Int1() - Number of instructions to step.
+
+@leave one of the system wide error codes
+
+*/
+void CSecuritySvrSession::StepL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::StepL()\n" );
+
+ const TThreadId threadId = ReadTThreadIdL(aMessage, 0);
+ const TInt32 numSteps = aMessage.Int1();
+
+ CheckAttachedL(threadId, aMessage, EFalse);
+
+ User::LeaveIfError(Server().iKernelDriver.Step( threadId, numSteps ));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+ * This checks whether or not the agent is permitted access to the flash partition
+ * @return KErrNone if allowed, otherwise one of the system wide error codes
+ * @leave one of the system wide error codes
+ */
+TInt CSecuritySvrSession::CheckFlashAccessPermissionL(const RThread& aClientThread)
+ {
+ // Read the OEM Debug token capabilities (if any)
+ GetDebugAgentOEMTokenCapsL();
+
+ if(Server().OEMTokenPermitsFlashAccessL((iOEMDebugCapabilities)))
+ {
+ return KErrNone;
+ }
+
+ return KErrPermissionDenied;
+ }
+
+/**
+Purpose: Read the crash log from the crash flash partition
+@param aMessage.Int0() - Position to read from.
+@param aMessage.Ptr1() - Buffer to hold the data retrieved
+@param aMessage.Int2() - Size of the data to read.
+
+@leave one of the system wide error codes
+*/
+void CSecuritySvrSession::ReadCrashLogL (const RMessage2& aMessage)
+ {
+ //get the debug agent's thread and push handle onto clean up stack
+ RThread clientThread;
+ User::LeaveIfError(aMessage.Client(clientThread));
+ CleanupClosePushL(clientThread);
+
+ TInt err = CheckFlashAccessPermissionL(clientThread);
+
+ CleanupStack::PopAndDestroy(&clientThread);
+
+ if(KErrNone != err)
+ {
+ LOG_MSG2( "CSecuritySvrSession::ReadCrashLogL() Access Not Granted - [%d]\n", err );
+ aMessage.Complete(err);
+ return;
+ }
+
+ //Check whether drive connected.
+ if(!iCrashConnected)
+ ConnectCrashPartitionL();
+
+ TInt readPosition = aMessage.Int0(); //read position
+
+ TInt readSize = aMessage.Int2(); //read size
+
+ RBuf8 readBuf;
+ readBuf.CreateL(readSize);
+ readBuf.CleanupClosePushL();
+
+ err = iLocalDrive.Read (readPosition, readSize, readBuf);
+
+ //write the list data back
+ aMessage.WriteL (1, readBuf);
+
+ CleanupStack::PopAndDestroy (&readBuf);
+
+ //Complete message
+ aMessage.Complete(err);
+ }
+/**
+Purpose: Function to write the crash config to the crash flash partition
+
+@param aMessage.Int0() - write position in bytes from start position in flash partition.
+@param aMessage.Ptr1() - Buffer containing the data to be written onto the flash.
+ The size could be 0 if only flash partition size is needed.
+@param aMessage.Int2() - returns the size of the flash partition.
+
+@leave one of the system wide error codes
+*/
+void CSecuritySvrSession::WriteCrashConfigL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::WriteCrashConfigL()\n" );
+
+ //get the debug agent's thread and push handle onto clean up stack
+ RThread clientThread;
+ User::LeaveIfError(aMessage.Client(clientThread));
+ CleanupClosePushL(clientThread);
+
+ TInt err = CheckFlashAccessPermissionL(clientThread);
+
+ CleanupStack::PopAndDestroy(&clientThread);
+
+ if(KErrNone != err)
+ {
+ LOG_MSG2( "CSecuritySvrSession::WriteCrashConfigL() Access Not Granted - [%d]\n", err );
+ aMessage.Complete(err);
+ return;
+ }
+
+ //Check whether drive connected.
+ if(!iCrashConnected)
+ ConnectCrashPartitionL();
+
+ // Get the length of the buffer
+ TInt deslen = aMessage.GetDesLengthL(1);
+
+ RBuf8 dataBuf;
+ dataBuf.CreateL(deslen);
+ dataBuf.CleanupClosePushL();
+
+ // data to be written to flash
+ aMessage.ReadL(1,dataBuf);
+
+ TUint32 position = aMessage.Int0(); //position to start from
+
+ err = iLocalDrive.Write(position,(const TDesC8&)dataBuf);
+
+ TPtr8 dataSize((TUint8*)&deslen,4, 4);
+
+ //write the size of the data written back
+ aMessage.WriteL(2,dataSize);
+
+ //destroy buffer
+ CleanupStack::PopAndDestroy(&dataBuf);
+
+ aMessage.Complete(err);
+ }
+/**
+Purpose: Method to erase the crash flash block
+
+@param aMessage.Int0() - write position in bytes from start position in flash partition.
+@param aMessage.Int2() - Number of blocks to erase.
+
+@leave one of the system wide error codes
+*/
+
+void CSecuritySvrSession::EraseCrashLogL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::EraseCrashLogL()\n" );
+
+ //get the debug agent's thread and push handle onto clean up stack
+ RThread clientThread;
+ User::LeaveIfError(aMessage.Client(clientThread));
+ CleanupClosePushL(clientThread);
+
+ TInt err = CheckFlashAccessPermissionL(clientThread);
+
+ CleanupStack::PopAndDestroy(&clientThread);
+
+ if(KErrNone != err)
+ {
+ LOG_MSG2( "CSecuritySvrSession::EraseCrashLogL() Access Not Granted - [%d]\n", err );
+ aMessage.Complete(err);
+ return;
+ }
+
+ //Check whether drive connected.
+ if(!iCrashConnected)
+ ConnectCrashPartitionL();
+
+ TInt64 position = aMessage.Int0();
+ TInt size = aMessage.Int1();
+
+ //Format drive
+ err = iLocalDrive.Format(position,size*iCaps.iEraseBlockSize);
+
+ aMessage.Complete(err);
+ }
+
+/**
+Purpose: Method to erase the entire crash flash block
+@leave one of the system wide error codes
+*/
+
+void CSecuritySvrSession::EraseEntireCrashLogL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::EraseEntireCrashLogL()\n" );
+
+ //get the debug agent's thread and push handle onto clean up stack
+ RThread clientThread;
+ User::LeaveIfError(aMessage.Client(clientThread));
+ CleanupClosePushL(clientThread);
+
+ TInt err = CheckFlashAccessPermissionL(clientThread);
+
+ CleanupStack::PopAndDestroy(&clientThread);
+
+ if(KErrNone != err)
+ {
+ LOG_MSG2( "CSecuritySvrSession::EraseEntireCrashLogL() Access Not Granted - [%d]\n", err );
+ aMessage.Complete(err);
+ return;
+ }
+
+ //Check whether drive connected.
+ if(!iCrashConnected)
+ ConnectCrashPartitionL();
+
+ TUint numberBlocks = iCaps.iSize /iCaps.iEraseBlockSize;
+
+ //Format drive
+ for(TInt i = 0; i < numberBlocks; i++)
+ {
+ err = iLocalDrive.Format(i*iCaps.iEraseBlockSize,iCaps.iEraseBlockSize);
+ if(KErrNone != err)
+ {
+ RDebug::Printf("err = %d", err);
+ aMessage.Complete(err);
+ return;
+ }
+ }
+
+
+ aMessage.Complete(err);
+ }
+
+
+/**
+Purpose: Kill a specified process
+
+@param aMessage.Ptr0() - Process Id of the thread to be stepped
+@param aMessage.Int1() - Reason code to supply when killing the process.
+
+@leave one of the system wide error codes
+
+*/
+void CSecuritySvrSession::KillProcessL(const RMessage2& aMessage)
+ {
+ LOG_MSG( "CSecuritySvrSession::KillProcessL()\n" );
+
+ const TProcessId processId = ReadTProcessIdL(aMessage, 0);
+ const TInt32 reason = aMessage.Int1();
+
+ CheckAttachedL(processId, aMessage, EFalse);
+
+ User::LeaveIfError(Server().iKernelDriver.KillProcess( processId, reason ));
+
+ aMessage.Complete(KErrNone);
+ }
+
+/** Gets the secure id of aFileName
+ @param aFileName file name of executable to get SID for
+ @param aSecureId on return will contain the SID of aFileName
+
+ @leave one of the system wide error codes
+ */
+void CSecuritySvrSession::GetSecureIdL(const TDesC& aFileName, TUid& aSecureId)
+ {
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ RFile targetExe;
+ OpenFileHandleL(aFileName, fs, targetExe);
+ CleanupClosePushL(targetExe);
+
+ // Read in the entire header
+ RBuf8 e32HdrBuf;
+ e32HdrBuf.CreateL(RLibrary::KRequiredImageHeaderSize);
+ e32HdrBuf.CleanupClosePushL();
+
+ // Read the entire header as far as possible
+ TInt err = targetExe.Read(e32HdrBuf);
+ if (err != KErrNone)
+ {
+ // Could not read the file
+ LOG_MSG("CSecuritySvrSession::GetSecureIdL - Failed to read executable\n");
+
+ User::Leave(err);
+ }
+
+ if(!CheckSufficientData(e32HdrBuf, IsExecutableXipL(targetExe)))
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ aSecureId = GetSecureIdL(e32HdrBuf, IsExecutableXipL(targetExe));
+
+ CleanupStack::PopAndDestroy(3, &fs);
+ }
+
+/** Get the secure id from aHeaderData
+ @param aHeaderData an executable's header data to read SID from
+ @param aXip indication of whether the header data is from an XIP file
+
+ @return secure ID from aHeaderData
+ */
+TUid CSecuritySvrSession::GetSecureIdL(const TDesC8& aHeaderData, TBool aXip)
+ {
+ if(!CheckSufficientData(aHeaderData, aXip))
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ if (aXip)
+ {
+ TRomImageHeader* hdr = (TRomImageHeader*)aHeaderData.Ptr();
+ return TUid::Uid(hdr->iS.iSecureId);
+ }
+ else
+ {
+ // it is an epoc32 image
+ E32ImageHeaderV* hdr = (E32ImageHeaderV*)aHeaderData.Ptr();
+ return TUid::Uid(hdr->iS.iSecureId);
+ }
+ }
+
+/**
+@param aMessage contains:
+ * aMessage.Ptr0() a TListDetails object
+ * aMessage.Ptr1() a client supplied TDes8 for the driver to return data in
+ * aMessage.Ptr2() a TUint32 for the driver to return the size of the requested listing's data in
+
+@leave KErrTooBig if the buffer passed as argument 1 of aMessage is too
+ small to contain the requested data,
+ KErrNoMemory if a temporary buffer could not be allocated,
+ or one of the other system wide error codes
+*/
+void CSecuritySvrSession::GetListL(const RMessage2& aMessage)
+ {
+ LOG_MSG("CSecuritySvrSession::GetListL()");
+
+ // buffer to write list data into before copying back to agent
+ RBuf8 listDetailsBuf;
+
+ //allocate buffer
+ listDetailsBuf.CreateL(sizeof(TListDetails));
+
+ // Do the right cleanup if anything subsequently goes wrong
+ listDetailsBuf.CleanupClosePushL();
+
+ //read the data from the client thread
+ aMessage.ReadL(0, listDetailsBuf);
+ TListDetails* listDetails = (TListDetails*)listDetailsBuf.Ptr();
+
+ //get the type of list requested
+ TListId type = (TListId)aMessage.Int0();
+
+ //create a buffer to store the data in
+ RBuf8 buffer;
+ buffer.CreateL(aMessage.GetDesMaxLength(1));
+ buffer.CleanupClosePushL();
+
+ //create a temporary variable to potentially store data length in
+ TUint32 size = 0;
+
+ TInt err = KErrNone;
+
+ // the executables list is generated in the DSS rather than in the driver
+ // so is treated separately
+ if(listDetails->iListId == EExecutables)
+ {
+ if(listDetails->iListScope != EScopeGlobal)
+ {
+ User::Leave(KErrArgument);
+ }
+ if(listDetails->iTargetId != 0)
+ {
+ User::Leave(KErrArgument);
+ }
+ err = GetExecutablesListL(buffer, size);
+ }
+ else
+ {
+ err = Server().iKernelDriver.GetList(listDetails->iListId, listDetails->iListScope, listDetails->iTargetId, iDebugAgentProcessId, buffer, size);
+ }
+
+ if(err == KErrNone)
+ {
+ //write the list data back
+ aMessage.WriteL(1, buffer);
+ }
+
+ TPtr8 sizePtr((TUint8*)&size, sizeof(TUint32), sizeof(TUint32));
+ //write size back to agent
+ aMessage.WriteL(2, sizePtr);
+
+ CleanupStack::PopAndDestroy(&buffer);
+ CleanupStack::PopAndDestroy(&listDetailsBuf);
+
+ aMessage.Complete(err);
+ }
+
+/**
+Gets the executables list and returns it in aBuffer if it's big enough
+
+@param aBuffer caller supplied buffer to write data into
+@param aSize on return contains the size of the data in the buffer, or the
+ size that the buffer would need to be to contain the data
+
+@return KErrNone on success, or KErrTooBig if the requested data will not fit in aBuffer
+
+@leave one of the system wide error codes
+*/
+TInt CSecuritySvrSession::GetExecutablesListL(TDes8& aBuffer, TUint32& aSize) const
+ {
+ LOG_MSG("CSecuritySvrSession::GetExecutablesList()");
+
+ //initialise values and connect to file system
+ aSize = 0;
+ aBuffer.SetLength(0);
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ // uids corresponding to executable image
+ TUidType uids(KExecutableImageUid, KNullUid, KNullUid);
+
+ //create a string containing the directory name. The drive letter is represented
+ //by X but will be replaced by the appropriate drive letter for each drive
+ _LIT(KColonSysBin,":\\sys\\bin\\");
+
+ //create a modifiable copy of KColonSysBin, preceeded by an empty space for the drive letter
+ RBuf dirName;
+ dirName.CreateL(1 + KColonSysBin().Length());
+ dirName.CleanupClosePushL();
+
+ //set the length to 1 (to later fill with the drive letter) and then append KColonSysBin
+ dirName.SetLength(1);
+ dirName.Append(KColonSysBin());
+
+ //get the list of valid drives for the device
+ TDriveList driveList;
+ User::LeaveIfError(fs.DriveList(driveList));
+
+ //check each valid sys/bin directory for executables
+ for(TInt i=0; i<KMaxDrives; i++)
+ {
+ //if the drive is not valid then skip this drive
+ if(!driveList[i])
+ {
+ //skip processing this drive
+ continue;
+ }
+
+ //get the drive letter and insert it as the drive letter for dirName
+ TChar driveLetter;
+ User::LeaveIfError(fs.DriveToChar(i, driveLetter));
+ dirName[0] = (TUint)driveLetter;
+
+ //get a list of the exes in this drive's sys/bin directory
+ CDir* localDir = NULL;
+ TInt err = fs.GetDir(dirName, uids, ESortByName, localDir);
+ if(KErrNoMemory == err)
+ {
+ User::Leave(err);
+ }
+ if(!localDir)
+ {
+ //skip processing this drive
+ continue;
+ }
+
+ //push onto cleanup stack in case we leave
+ CleanupStack::PushL(localDir);
+
+ //iterate through the files
+ for(TInt j=0; j<localDir->Count(); j++)
+ {
+ //will store x:\sys\bin\<file-name> type string
+ RBuf fullPathName;
+
+ TUint16 nameLength = dirName.Length() + (*localDir)[j].iName.Length();
+ fullPathName.CreateL(nameLength);
+ fullPathName.CleanupClosePushL();
+ fullPathName.Copy(dirName);
+ fullPathName.Append((*localDir)[j].iName);
+
+ //add the data to the buffer
+ AppendExecutableData(aBuffer, aSize, fullPathName);
+
+ //do cleanup
+ CleanupStack::PopAndDestroy(&fullPathName);
+ }
+
+ //do cleanup
+ CleanupStack::PopAndDestroy(localDir);
+ }
+
+ //do cleanup
+ CleanupStack::PopAndDestroy(2, &fs);
+
+ //return appropriate value as to whether the kernel's data was too big
+ return (aSize <= aBuffer.MaxLength()) ? KErrNone : KErrTooBig;
+ }
+
+
+/**
+ Append data to aBuffer and update size of aSize if the data will fit. If it will
+ not fit then just puts the nee size in aSize.
+
+ @param aBuffer buffer to append the data to
+ @param aSize on return contains the new size of the buffer if the data could be
+ appended, otherwise aSize is updated to reflect the size the buffer would have if
+ the data had fitted.
+ @param aEntryName file name of the entry to add to the buffer
+ */
+void CSecuritySvrSession::AppendExecutableData(TDes8& aBuffer, TUint32& aSize, const TDesC& aEntryName) const
+ {
+ //update aSize to include the size of the data for this entry
+ aSize = Align4(aSize + sizeof(TExecutablesListEntry) + (2*aEntryName.Length()) - sizeof(TUint16));
+
+ //if the data will fit, and we haven't already stopped putting data in, then append the data,
+ //if we've stopped putting data in then aSize will be bigger than aBuffer.MaxLength()
+ if(aSize <= aBuffer.MaxLength())
+ {
+ TExecutablesListEntry& entry = *(TExecutablesListEntry*)(aBuffer.Ptr() + aBuffer.Length());
+ //check whether an agent has registered to actively debug fullPathName
+ TBool activelyDebugged = IsDebugged(aEntryName, EFalse);
+ entry.iIsActivelyDebugged = activelyDebugged ? 1 : 0;
+
+ //check whether any agents have registered to passively debug fullPathName
+ TBool passivelyDebugged = IsDebugged(aEntryName, ETrue);
+ entry.iIsPassivelyDebugged = passivelyDebugged ? 1 : 0;
+
+ entry.iNameLength = aEntryName.Length();
+ TPtr name(&(entry.iName[0]), aEntryName.Length(), aEntryName.Length());
+ name = aEntryName;
+ //pad the buffer to a four byte boundary
+ aBuffer.SetLength(aSize);
+ }
+ }
+/**
+Helper function
+
+Write data back to the thread that owns aMessage
+
+@param aMessage the message which is passed between processes
+@param aIndex the message slot which the data will be passed back in
+@param aPtr pointer to data in this thread to be written into aMessage
+@param aPtrSize size in bytes of the data to be written
+
+@leave one of the system wide error codes
+*/
+void CSecuritySvrSession::WriteDataL(const RMessage2& aMessage, const TInt aIndex, const TAny* aPtr, const TUint32 aPtrSize) const
+ {
+ TPtr8 dataPtr((TUint8*)aPtr, aPtrSize, aPtrSize);
+
+ aMessage.WriteL(aIndex, dataPtr);
+ }
+
+/**
+Helper function.
+
+Checks whether the debug agent (the owner of the aMessage) is attached to the
+thread with thread id of aThreadId.
+
+@param aThreadId thread ID of target debug thread
+@param aMessage message owned by the debug agent
+@param aPassive indicates whether to check if attached passively or actively
+
+@leave KErrPermissionDenied if the agent is not attached to the process,
+ KErrNoMemory if the security server could not be accessed
+*/
+void CSecuritySvrSession::CheckAttachedL(const TThreadId aThreadId, const RMessage2& aMessage, const TBool aPassive) const
+ {
+ //check that the agent has attached to the target process
+ if(! Server().CheckAttached(aThreadId, aMessage, aPassive))
+ {
+ LOG_MSG("CSecuritySvrSession::CheckAttachedL() failed");
+ User::Leave(KErrPermissionDenied);
+ }
+ }
+
+/**
+Helper function.
+
+Checks whether the debug agent (the owner of the aMessage) is attached to the
+process with process id of aProcessId.
+
+@param aProcessId process ID of target debug thread
+@param aMessage message owned by the debug agent
+@param aPassive indicates whether to check if attached passively or actively
+
+@leave KErrPermissionDenied if the agent is not attached to the process,
+ KErrNoMemory if the security server could not be accessed
+*/
+void CSecuritySvrSession::CheckAttachedL(const TProcessId aProcessId, const RMessage2& aMessage, const TBool aPassive) const
+ {
+
+ //check that the agent has attached to the target process
+ if(! Server().CheckAttached(aProcessId, aMessage, aPassive))
+ {
+ LOG_MSG("CSecuritySvrSession::CheckAttachedL() (process) failed");
+ User::Leave(KErrPermissionDenied);
+ }
+ }
+
+/**
+Check whether the debug agent is permitted to attach to the target process.
+Note that this function does not actually attach the agent to the process, it
+simply tests whether an attach call would potentially be successful.
+
+Currently this method returns ETrue in all cases but will be updated once
+the security checking framework is in place.
+
+@param aDebugAgentProcessId process id of the debug agent
+@param aTargetProcessName original file name of the target process
+
+@return ETrue if the debug agent would be allowed to attch to the target process,
+ EFalse otherwise
+*/
+TBool CSecuritySvrSession::PermitDebugL(const TProcessId aDebugAgentProcessId, const TDesC& aTargetProcessName) const
+ {
+ return ETrue;
+ }
+
+/**
+Helper function
+
+Validates that the memory info passed in meets the debug driver's requirements
+
+@param aMemoryInfo memory info passed in from client
+
+@leave KErrArgument if:
+ * size is zero
+ * size is greater than the max block size
+ * size + address > 0xffffffff
+ * address is not access size aligned
+ * size is not a multiple of the access size
+ KErrNotSupported if:
+ * iAccess is not TAccess::EAccess32
+ * iEndianess is not TEndianess::EEndLE8
+ KErrUnknown if:
+ * the max memory block size cannot be determined
+ or one of the other system wide error codes
+*/
+void CSecuritySvrSession::ValidateMemoryInfoL(const TThreadId aThreadId, const TMemoryInfo &aMemoryInfo, const TBool aReadOperation)
+ {
+ //check size is not 0
+ if(aMemoryInfo.iSize == 0)
+ User::Leave(KErrArgument);
+
+ //get the max block size supported
+ TUint32 maxSize = 0;
+ User::LeaveIfError(Server().iKernelDriver.GetMemoryOperationMaxBlockSize(maxSize));
+
+ //check that the block size given is less than the max block size
+ if(aMemoryInfo.iSize > maxSize)
+ User::Leave(KErrArgument);
+
+ //must ensure that address + size <= 0xffffffff as will attempt to
+ //read past 0xffffffff, which wouldn't be good
+ TUint32 maxAddress = (~aMemoryInfo.iSize) + 1;
+ if(aMemoryInfo.iAddress > maxAddress)
+ User::Leave(KErrArgument);
+
+ //check that arguments are supported
+ if(aMemoryInfo.iAccess != EAccess32)
+ User::Leave(KErrNotSupported);
+
+ if(aMemoryInfo.iEndianess != EEndLE8)
+ User::Leave(KErrNotSupported);
+
+ //check that address is multiple of access size
+ TInt addressIndicator = aMemoryInfo.iAddress % aMemoryInfo.iAccess;
+ if(addressIndicator != 0)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ //check that size is multiple of access size
+ TInt sizeIndicator = aMemoryInfo.iSize % aMemoryInfo.iAccess;
+ if(sizeIndicator != 0)
+ User::Leave(KErrArgument);
+ }
+
+/**
+Helper function
+
+Validates that the three buffers relating to reading register data are of
+appropriate sizes, and calculates the number of registers being requested.
+
+@param aMessage message which in offsets 1, 2 and 3 contains descriptors
+@param aNumberOfRegisters if the function returns with KErrNone this will
+ contain the number of registers being requested, guaranteed to be non-zero
+
+@leave KErrArgument if descriptors do not represent the same number of
+ registers, if any of the descriptors have max length of 0, if any of
+ the descriptors have max lengths which are not multiples of their data
+ type's size or if any of the descriptors have max lengths greater than
+ the max block size for memory operations
+ or one of the other system wide error codes if there were problems
+ in getting the descriptors' lengths.
+*/
+void CSecuritySvrSession::ValidateRegisterBuffersL(const RMessage2& aMessage, TUint32& aNumberOfRegisters)
+ {
+ //get lengths of buffers, if error occurs returned value will be less then zero
+ TInt idsBufferLength = aMessage.GetDesMaxLength(1);
+ if(idsBufferLength < 0)
+ {
+ User::Leave(idsBufferLength);
+ }
+ TInt valuesBufferLength = aMessage.GetDesMaxLength(2);
+ if(valuesBufferLength < 0)
+ {
+ User::Leave(valuesBufferLength);
+ }
+ TInt flagsBufferLength = aMessage.GetDesMaxLength(3);
+ if(flagsBufferLength < 0)
+ {
+ User::Leave(flagsBufferLength);
+ }
+
+ //get the max block size supported
+ TUint32 maxSize = 0;
+ User::LeaveIfError(Server().iKernelDriver.GetMemoryOperationMaxBlockSize(maxSize));
+
+ //check none of the descriptors have size greater than the max block size
+ if((idsBufferLength > maxSize) || (valuesBufferLength > maxSize) || (flagsBufferLength > maxSize))
+ User::Leave(KErrArgument);
+
+ //get sizes of the three types of data the buffers represent arrays of
+ //and validate that the buffer lengths are multiples of the data sizes
+ TUint idSize = sizeof(TRegisterInfo);
+ if(idsBufferLength % idSize != 0)
+ User::Leave(KErrArgument);
+
+ TUint flagSize = sizeof(TUint8);
+ if(flagsBufferLength % flagSize != 0)
+ User::Leave(KErrArgument);
+
+ //perform check on id buffer length
+ if(idsBufferLength == 0)
+ User::Leave(KErrArgument);
+
+ //calculate number of registers being requested
+ aNumberOfRegisters = idsBufferLength / idSize;
+
+ //check flags buffer is of appropriate size
+ if(flagsBufferLength != (aNumberOfRegisters * flagSize))
+ User::Leave(KErrArgument);
+ }
+
+/**
+Establish whether any agents have registered to debug the specified aFileName
+
+@param aFileName originating file name of the target process
+@param aPassive indicates whether to check if there has been active attachment,
+or passive attachment.
+
+@return ETrue if aFileName is being debugged, EFalse otherwise
+
+*/
+TBool CSecuritySvrSession::IsDebugged(const TDesC& aFileName, const TBool aPassive) const
+ {
+ //check whether the target process is being debugged
+ return Server().IsDebugged(aFileName, aPassive);
+ }
+
+/**
+ Helper function which reads a TThreadId object from a client
+
+ @param aMessage the message object containing the reference to the TThreadId
+ @param aIndex the message argument containing the reference
+
+ @return the TThreadId passed in by the client
+ @leave KErrArgument if aIndex is outside of the valid range
+ */
+TThreadId CSecuritySvrSession::ReadTThreadIdL(const RMessagePtr2& aMessage, const TInt aIndex) const
+ {
+ //create a temporary TThreadId to read the data into
+ TThreadId tempThreadId;
+ TPtr8 threadIdPtr((TUint8*)&tempThreadId, sizeof(TThreadId));
+
+ // read the data in from the client
+ aMessage.ReadL(aIndex, threadIdPtr);
+
+ return tempThreadId;
+ }
+
+/**
+ Helper function which reads a TProcessId object from a client
+
+ @param aMessage the message object containing the reference to the TProcessId
+ @param aIndex the message argument containing the reference
+
+ @return the TProcessId passed in by the client
+ @leave KErrArgument if aIndex is outside of the valid range
+ */
+TProcessId CSecuritySvrSession::ReadTProcessIdL(const RMessagePtr2& aMessage, const TInt aIndex) const
+ {
+ //create a temporary TProcessId to read the data into
+ TProcessId tempProcessId;
+ TPtr8 processIdPtr((TUint8*)&tempProcessId, sizeof(TProcessId));
+
+ // read the data in from the client
+ aMessage.ReadL(aIndex, processIdPtr);
+
+ return tempProcessId;
+ }
+
+// End of file - c_security_svr_session.cpp