--- a/debugsrv/runmodedebug/securityserver/src/c_security_svr_server.cpp Tue Aug 31 16:45:49 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,685 +0,0 @@
-// Copyright (c) 2006-2009 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 server implementation.
-//
-//
-
-/**
- @file
- @internalTechnology
- @released
-*/
-
-#include <e32base.h>
-#include <e32base_private.h>
-#include <rm_debug_api.h>
-#include "c_process_pair.h"
-#include "c_security_svr_session.h"
-#include "c_security_svr_server.h"
-#include "rm_debug_logging.h"
-
-using namespace Debug;
-
-/**
-Server constructor, sessions are created as ESharableSessions, meaning that
-each session will be used by at most one debug agent
-*/
-CSecuritySvrServer::CSecuritySvrServer(CActive::TPriority aActiveObjectPriority)
- : CServer2(aActiveObjectPriority, ESharableSessions),
- iSessionCount(0),
- iShutdown()
- {
- LOG_MSG("CSecuritySvrServer::CSecuritySvrServer()\n");
- }
-
-/**
-Standard implementation
-
-@return pointer to new CSecuritySvrServer object
-*/
-CSecuritySvrServer* CSecuritySvrServer::NewLC()
- {
- LOG_MSG("CSecuritySvrServer::NewLC()\n");
-
- CSecuritySvrServer* self=new(ELeave) CSecuritySvrServer(EPriorityStandard);
- CleanupStack::PushL(self);
- self->ConstructL();
- return self;
- }
-
-/**
-Server destructor, performs cleanup for the server
-*/
-CSecuritySvrServer::~CSecuritySvrServer()
- {
- LOG_MSG("CSecuritySvrServer::~CSecuritySvrServer()\n");
-
- // stop the kernel side driver
- iKernelDriver.Close();
- User::FreeLogicalDevice(KDebugDriverName);
-
- //deallocate both the debug maps
- iPassiveDebugMap.ResetAndDestroy();
- iActiveDebugMap.ResetAndDestroy();
- }
-
-/**
-Starts the server and constructs and starts the servers shutdown timer
-*/
-void CSecuritySvrServer::ConstructL()
- {
- LOG_MSG("CSecuritySvrServer::ConstructL()");
-
- StartL(KSecurityServerName);
- iShutdown.ConstructL();
- iShutdown.Start();
-
- //load the kernel driver
- TInt err = User::LoadLogicalDevice(KDebugDriverFileName);
- if(! ((KErrNone == err) || (KErrAlreadyExists == err)))
- {
- User::Leave(err);
- }
- //create an information object for initialising the driver
- TRM_DebugDriverInfo driverInfo;
- driverInfo.iUserLibraryEnd = 0;
- User::LeaveIfError(iKernelDriver.Open(driverInfo));
- }
-
-/**
-Creates a new session with the DSS. A version check is done to ensure that an
-up to date version of the DSS is available (according to the DA's needs).
-The device driver is loaded if necessary and a session with the server and a
-handle to the driver opened.
-
-@param aRequiredVersion the minimal version of the DSS required by the DA
-
-@return a pointer to the new sever session, or NULL if any of the
- initialisation process failed
-*/
-CSession2* CSecuritySvrServer::NewSessionL(const TVersion& aRequiredVersion, const RMessage2& aMessage) const
-//
-// Session constructor
-//
- {
- LOG_ARGS("version=%d.%d.%d", aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild);
-
- //assert compatible version
- TVersion currentVersion(KDebugServMajorVersionNumber, KDebugServMinorVersionNumber, KDebugServPatchVersionNumber);
- if(!User::QueryVersionSupported(currentVersion, aRequiredVersion))
- {
- LOG_MSG("Requested version not compatible with this version. Asked for %d.%d.%d but this is %d.%d.%d", aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild, KDebugServMajorVersionNumber, KDebugServMinorVersionNumber, KDebugServPatchVersionNumber);
- User::Leave(KErrNotSupported);
- }
-
- //get the debug agent's process id
- RThread clientThread;
- User::LeaveIfError(aMessage.Client(clientThread));
- CleanupClosePushL(clientThread);
- RProcess clientProcess;
- User::LeaveIfError(clientThread.Process(clientProcess));
- CleanupStack::PopAndDestroy(&clientThread);
- TProcessId processId = clientProcess.Id();
- clientProcess.Close();
-
- //create session
- LOG_MSG("About to call new(ELeave) CSecuritySvrSession()");
- CSecuritySvrSession* servSession = new(ELeave) CSecuritySvrSession(processId);
-
- CleanupStack::PushL(servSession);
- servSession->ConstructL();
- CleanupStack::Pop(servSession);
- return servSession;
- }
-
-/**
-Manages requests from debug agents to attach to target debug processes
-
-Given the debug agent process ID and the target process name:
-(1) checks whether the pair is already in either of the debug maps, if so
- then returns KErrAlreadyExists
-(2) if aPassive == ETrue then just add the pair to the passive map and return
- whatever the return value of the array write was
-(3) if aPassive == EFalse then check whether the target debug process is
- already reserved by another debug agent. If it is then return KErrInUse,
- otherwise add the pair to the active debug map and return the status
- value of the array write.
-
-@param aTargetProcessName original FileName of the process to attach to
-@param aDebugAgentProcessId process ID of the debug agent
-@param aPassive ETrue if wish to attach passively, EFalse otherwise
-
-@return KErrNone if successfully attached, otherwise another system wide error
- code as above
-*/
-TInt CSecuritySvrServer::AttachProcessL(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId, const TBool aPassive)
- {
- //store the pair of values
- LOG_MSG3("CSecuritySvrServer::AttachProcessL() 0x%lx aPassive=%d", aDebugAgentProcessId.Id(), aPassive);
-
- CProcessPair *processPair = CProcessPair::NewL(aTargetProcessName, aDebugAgentProcessId);
- if(processPair == NULL)
- return KErrNoMemory;
-
- //check whether the pair already exists in the active debug map
- for(TInt i=0; i<iActiveDebugMap.Count(); i++)
- {
- // Note that the equality is of the debug agent id and the proc name
- if(*processPair == *(iActiveDebugMap[i]))
- {
- //process already exists
- LOG_MSG( " AttachProcessL() error : KErrAlreadyExists in active map\n" );
- delete processPair;
- return KErrAlreadyExists;
- }
- }
-
- //check whether the pair already exists in the passive map
- for(TInt i=0; i<iPassiveDebugMap.Count(); i++)
- {
- if(*processPair == *(iPassiveDebugMap[i]))
- {
- //process already exists
- LOG_MSG( " AttachProcessL() error : KErrAlreadyExists in passive map\n" );
- delete processPair;
- return KErrAlreadyExists;
- }
- }
-
- if(aPassive)
- {
- //just add the pair and return
- TInt err = iPassiveDebugMap.Append(processPair);
- if(err != KErrNone)
- {
- // couldn't add pair for some unknown reason, so delete the pair
- LOG_MSG2( " AttachProcessL() error %d appending passive process pair", err );
- delete processPair;
- }
- return err;
- }
- else
- {
- //check whether the process Id has already been reserved
- for(TInt i=0; i<iActiveDebugMap.Count(); i++)
- {
- // Now check if this is already debugged, but only if its for a particular process.
- // We can have several entries from AttachAll calls, and its ok to add them
- if( (!processPair->ProcessNameMatches(_L("*"))) &&
- (processPair->ProcessNameMatches(*(iActiveDebugMap[i])) ) )
- {
- //process already being debugged
- LOG_MSG( " AttachProcessL() error : process already being debugged" );
- delete processPair;
- return KErrInUse;
- }
- }
- //try to add the pair.
- TInt err = iActiveDebugMap.Append(processPair);
- if(err != KErrNone)
- {
- // couldn't add pair for some unknown reason, so delete the pair
- LOG_MSG2( " AttachProcessL() error %d inserting active process pair", err );
- delete processPair;
- }
- return err;
- }
- }
-
-/*
-Detach from debugging the specified process
-
-@param aTargetProcessName name of the process to detach from
-@param aDebugAgentProcessId process ID of the debug agent
-
-@return KErrNone if successfully detached, KErrNotFound if an attempt is made
- to detach from a process which the debug agent hasn't previously attached to
-*/
-TInt CSecuritySvrServer::DetachProcess(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId)
- {
- LOG_MSG2( "CSecuritySvrServer::DetachProcess() for agent with id 0x%lx", aDebugAgentProcessId.Id() );
-
- //check whether the pair is in the active debug map
- for(TInt i=0; i<iActiveDebugMap.Count(); i++)
- {
- if(iActiveDebugMap[i]->Equals(aTargetProcessName, aDebugAgentProcessId))
- {
- //remove the process pair from the active debug map
- delete iActiveDebugMap[i];
- iActiveDebugMap.Remove(i);
- return KErrNone;
- }
- }
-
- //check whether the pair is in the passive debug map
- for(TInt i=0; i<iPassiveDebugMap.Count(); i++)
- {
- if(iPassiveDebugMap[i]->Equals(aTargetProcessName, aDebugAgentProcessId))
- {
- //remove the process pair from the active debug map
- delete iPassiveDebugMap[i];
- iPassiveDebugMap.Remove(i);
- return KErrNone;
- }
- }
-
- //process pair wasn't in either map
- return KErrNotFound;
- }
-
-/**
-Given a debug agent process ID, removes all references to that debug agent
-from the debug maps
-
-@param aMessage message from the debug agent
-
-@return returns KErrNone if successful, another system wide error code otherwise
-*/
-void CSecuritySvrServer::DetachAllProcesses(const TProcessId aDebugAgentProcessId)
- {
- //check whether the debug agent process ID is in the active debug map
- for(TInt i=iActiveDebugMap.Count()-1; i>=0; i--)
- {
- if(iActiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId))
- {
- //remove the process pair from the active debug map
- delete iActiveDebugMap[i];
- iActiveDebugMap.Remove(i);
- }
- }
-
- //check whether the debug agent process ID is in the passive debug map
- for(TInt i=iPassiveDebugMap.Count()-1; i>=0; i--)
- {
- if(iPassiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId))
- {
- //remove the process pair from the passive debug map
- delete iPassiveDebugMap[i];
- iPassiveDebugMap.Remove(i);
- }
- }
- }
-
-/*
-Check whether the specified debug agent is attaced to the specfied target
-process.
-
-@param aTargetThreadId thread ID of a thread in the target process
-@param aMessage a message which originates with the debug agent
-@param aPassive if EFalse then checks whether the debug agent is the active
- debugger of the target process. If ETrue then checks whether the debug
- agent is attached to the target process, irrespective of whether it is
- attached passively or actively
-
-@return ETrue if attached, EFalse otherwise
-*/
-TBool CSecuritySvrServer::CheckAttached(const TThreadId aTargetThreadId, const RMessage2& aMessage, const TBool aPassive)
- {
-
- //get a handle to the target thread
- RThread targetThread;
- TInt err = targetThread.Open(aTargetThreadId);
- if(err != KErrNone)
- {
- return EFalse;
- }
-
- //get a handle to the target process
- RProcess targetProcess;
- err = targetThread.Process(targetProcess);
- //finshed with the thread handle so close it
- targetThread.Close();
- if(err != KErrNone)
- return EFalse;
-
- //get the target process' file name
- TFileName targetFileName = targetProcess.FileName();
-
- // Tamperproofing. Ensure that the debug agent really has a superset
- // of the target process PlatSec capabilities, as authorised
- // by an OEM Debug Token (if any)
-
- TSecurityInfo targetSecInfo(targetProcess);
-
- // Now compare the capabilities, to ensure the DebugAgent has been authorised with
- // sufficient capabilities from its OEM Debug token
- CSecuritySvrSession* session = (CSecuritySvrSession*)aMessage.Session();
-
- // Presume we need to check the target process is debuggable unless a valid OEM Debug token in effect?
- if (!OEMTokenPermitsDebugL(session->GetOEMDebugCapabilities(), targetSecInfo.iCaps) )
- {
- // No debug token therefore check if the process is debuggable
- err = iKernelDriver.IsDebuggable(targetProcess.Id());
- }
-
- //finished with the process handle so close it
- targetProcess.Close();
-
- if (err != KErrNone)
- {
- // The process was not marked as debuggable by the loader, and the OEM
- // debug token did not override the lack of a debuggable bit.
- // The process was not marked as debuggable by the loader
- return EFalse;
- }
-
- return CheckAttachedProcess(targetFileName, aMessage, aPassive);
- }
-
-/*
-Check whether the specified debug agent is attaced to the specfied target
-process.
-
-@param aTargetProcessId process ID of the target process
-@param aMessage a message which originates with the debug agent
-@param aPassive if EFalse then checks whether the debug agent is the active
- debugger of the target process. If ETrue then checks whether the debug
- agent is attached to the target process, irrespective of whether it is
- attached passively or actively
-
-@return ETrue if attached, EFalse otherwise
-*/
-TBool CSecuritySvrServer::CheckAttached(const TProcessId aTargetProcessId, const RMessage2& aMessage, const TBool aPassive)
- {
- //get a handle to the target process
- RProcess targetProcess;
- TInt err =targetProcess.Open(aTargetProcessId);
- if(err != KErrNone)
- {
- return EFalse;
- }
-
- //get the target process' file name
- TFileName targetFileName = targetProcess.FileName();
-
- // Tamperproofing. Ensure that the debug agent really has a superset
- // of the target process PlatSec capabilities, as authorised
- // by an OEM Debug Token (if any)
-
- TSecurityInfo targetSecInfo(targetProcess);
-
- // Now compare the capabilities, to ensure the DebugAgent has been authorised with
- // sufficient capabilities from its OEM Debug token
- CSecuritySvrSession* session = (CSecuritySvrSession*)aMessage.Session();
-
- // Presume we need to check the target process is debuggable unless a valid OEM Debug token in effect?
- if ( !OEMTokenPermitsDebugL(session->GetOEMDebugCapabilities(), targetSecInfo.iCaps) )
- {
- // No debug token therefore check if the process is debuggable
- err = iKernelDriver.IsDebuggable(targetProcess.Id());
- }
-
- //finished with the process handle so close it
- targetProcess.Close();
-
- if (err != KErrNone)
- {
- return EFalse;
- }
-
- return CheckAttachedProcess(targetFileName, aMessage, aPassive);
- }
-
-/*
-Check whether the specified debug agent is attaced to the specfied target
-process.
-
-@param aTargetProcessName
-@param aMessage a message which originates with the debug agent
-
-@return ETrue if attached, EFalse otherwise
-*/
-TBool CSecuritySvrServer::CheckAttachedProcess(const TDesC& aTargetProcessName, const RMessage2& aMessage, const TBool aPassive) const
- {
- //get the debug agent's process id
- TProcessId clientProcessId = 0;
- TInt err = GetProcessIdFromMessage(clientProcessId, aMessage);
- if(err != KErrNone)
- return EFalse;
-
- //check permissions
- if(aPassive)
- return IsDebugger(aTargetProcessName, clientProcessId);
- else
- return IsActiveDebugger(aTargetProcessName, clientProcessId);
- }
-
-/**
-Tests whether the debug agent is attached actively to the target debug process
-
-@param aTargetProcessName target debug process' FileName
-@param aDebugAgentProcessId process ID of a debug agent
-
-@return ETrue if the specified debug agent is actively attached to the
- specified target debug process, EFalse otherwise
-*/
-TBool CSecuritySvrServer::IsActiveDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const
- {
- //check whether the pair is in the active debug map
- for(TInt i=0; i<iActiveDebugMap.Count(); i++)
- {
- // If both match, which can include aTargetProcessName being "*"
- if(iActiveDebugMap[i]->Equals(aTargetProcessName, aDebugAgentProcessId))
- {
- LOG_MSG2( "CSecuritySvrServer::IsActiveDebugger() for agent id 0x%lx matches name and pid",
- aDebugAgentProcessId.Id() );
- return ETrue;
- }
- // if the pid matches and the name in the map is "*", indicating that
- // this is an attach all agent, and thus debugging
- if( iActiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId) &&
- iActiveDebugMap[i]->ProcessNameMatches(_L("*")) )
- {
- LOG_MSG2( "CSecuritySvrServer::IsActiveDebugger() for AttachAll agent id 0x%lx",
- aDebugAgentProcessId.Id() );
- return ETrue;
- }
- }
- //not found so return false
- return EFalse;
- }
-
-/**
-Tests whether the target process is being debugged
-
-@param aTargetProcessName target process' FileName
-@param aPassive indicates whether to check for the process being actively debugged,
-or passively debugged
-
-@return ETrue if the specified target process is being debugged,
- EFalse otherwise
-*/
-TBool CSecuritySvrServer::IsDebugged(const TDesC& aTargetProcessName, const TBool aPassive) const
- {
- //get a reference to the appropriate list
- const RPointerArray<CProcessPair>& map = (aPassive) ? iPassiveDebugMap : iActiveDebugMap;
-
- //iterate through the map trying to match the aTargetProcessName
- for(TInt i=0; i<map.Count(); i++)
- {
- if(map[i]->ProcessNameMatches(aTargetProcessName))
- {
- return ETrue;
- }
- }
- return EFalse;
- }
-
-/**
-Tests whether the debug agent is attached to the target debug process
-
-@param aTargetProcessName target debug process' FileName
-@param aDebugAgentProcessId process ID of a debug agent
-
-@return ETrue if the specified debug agent is attached to the
- specified target debug process (regardless of whether it is attached
- passively or actively), EFalse otherwise
-*/
-TBool CSecuritySvrServer::IsDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const
- {
- //check whether the pair is in the active debug map
- if(IsActiveDebugger(aTargetProcessName, aDebugAgentProcessId))
- return ETrue;
-
- //check whether the pair is in the passive debug map
- for(TInt i=0; i<iPassiveDebugMap.Count(); i++)
- {
- if(iPassiveDebugMap[i]->Equals(aTargetProcessName, aDebugAgentProcessId))
- return ETrue;
- }
- //not found so return false
- return EFalse;
- }
-
-/**
-Decrements the server's count of how many sessions are connected to it and
-starts the shutdown timer if there are no sessions connected
-*/
-void CSecuritySvrServer::SessionClosed()
- {
- if(--iSessionCount < 1)
- {
- iShutdown.Start();
- }
- }
-
-/**
-Increments the servers count of how many sessions are connected to it and
-cancels the shutdown timer if it is running
-*/
-void CSecuritySvrServer::SessionOpened()
- {
- iSessionCount++;
- iShutdown.Cancel();
- }
-
-/**
- Get the process id of the thread which sent aMessage
- @param aProcessId process id of the thread which sent aMessage
- @param aMessage message object sent by thread
-
- @return KErrNone if aProcessId could be set, or one of the system wide error codes if not
- */
-TInt CSecuritySvrServer::GetProcessIdFromMessage(TProcessId& aProcessId, const RMessage2& aMessage) const
- {
- //get the debug agent's thread
- RThread clientThread;
- TInt err = aMessage.Client(clientThread);
- if(err != KErrNone)
- {
- return err;
- }
-
- //get the debug agent's process
- RProcess clientProcess;
- err = clientThread.Process(clientProcess);
-
- //finished with the thread handle so close it
- clientThread.Close();
-
- //check if there was an error from getting the process
- if(err != KErrNone)
- {
- return err;
- }
-
- //get the debug agent's process id
- aProcessId = clientProcess.Id();
-
- //finished with the process handle so close it
- clientProcess.Close();
-
- return KErrNone;
- }
-
-/**
- Helper function which determines whether the capabilities of the
- OEM Token are sufficient to permit debug of an application.
-
- Normally, we use the AllFiles capability as a proxy which
- means a Debug Agent can debug non-debuggable executables,
- provided it has a superset of the capabilities of the executable
- to be debugged.
-
- However, this causes the problem that all OEM Debug Tokens implicitly
- give the power to debug an AllFiles executable, even if all that
- is really needed is the power to debug an app with no capabilities,
- or capabilities other than AllFiles.
-
- To address this, we treat the AllFiles capability in a special way.
- The AllFiles capability in a token is taken to mean that an OEM has
- signed the token, and hence can debug other executables. But this does
- not inclue the ability to debug an AllFiles executable. To debug an AllFiles
- executable, the token must also have TCB.
-
- @param aTokenCaps - The PlatSec capabilities of a token
- @param aTargetCaps - The PlatSec capabilities of a target app to be debugged
-
- @return ETrue if authorised for debugging, EFalse otherwise.
-
- @leave Any system error code.
- */
-TBool CSecuritySvrServer::OEMTokenPermitsDebugL(const TCapabilitySet aTokenCaps, const TCapabilitySet aTargetCaps)
- {
- LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL\n");
-
- // Is the token valid - i.e. does it have AllFiles.
- if ( !aTokenCaps.HasCapability(ECapabilityAllFiles) )
- {
- // Token is not valid, as it does not have AllFiles.
- LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have AllFiles\n");
-
- return EFalse;
- }
-
- // Token MUST have a strict superset of capabilities
- if ( !aTokenCaps.HasCapabilities(aTargetCaps) )
- {
- // Token does not have at least all the capabilities of the target
- LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have superset of target capabilities\n");
-
- return EFalse;
- }
-
- // Special case: If the target has AllFiles, the Token must have TCB
- if ( aTargetCaps.HasCapability(ECapabilityAllFiles) )
- {
- // Target has AllFiles, so does the Token have TCB?
- if ( !aTokenCaps.HasCapability(ECapabilityTCB) )
- {
- // Token does not have TCB.
- LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have TCB when target has AllFiles\n");
-
- return EFalse;
- }
- }
-
- // If we have passed all the above tests, the token permits debug
- return ETrue;
- }
-
-/**
- * This looks at a debug tokens capability and ensures it is sufficient
- * to provide access to the flash partition
- * @param aTokenCaps Capabilties of the Token
- * @return TBool Whether or not flash access is permitted
- */
-TBool CSecuritySvrServer::OEMTokenPermitsFlashAccessL(const TCapabilitySet aTokenCaps)
- {
- //Must have TCB to access flash
- return aTokenCaps.HasCapability(ECapabilityTCB);
- }
-
-//eof
-