os/kernelhwsrv/kerneltest/e32test/secure/t_ipcsafety.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32test\secure\t_ipcsafety.cpp
sl@0
    15
// Overview:
sl@0
    16
// Test if it's possible for a thread in a server process to access the IPC alias
sl@0
    17
// region outside the control of the kernel.
sl@0
    18
// API Information:
sl@0
    19
// RMessage2
sl@0
    20
// Details:
sl@0
    21
// - Create a server which will take a long time IPCing any client request.
sl@0
    22
// - Create a high priority thread which will attempt to write to a given
sl@0
    23
// location in the IPC region, with an exception handler to retry if it fails.
sl@0
    24
// - Create a client process which connects to the server and offers a
sl@0
    25
// stack-based descriptor for IPC, as well as the address of another stack
sl@0
    26
// variable that should not be able to be accessed.
sl@0
    27
// - The bad writer will attempt to jump in and overwrite the variable,
sl@0
    28
// causing the client to return a detectable error.
sl@0
    29
// - Verify that this does not happen.
sl@0
    30
// Platforms/Drives/Compatibility:
sl@0
    31
// ARM with multiple memory model only.
sl@0
    32
// Assumptions/Requirement/Pre-requisites:
sl@0
    33
// Failures and causes:
sl@0
    34
// Base Port information:
sl@0
    35
// 
sl@0
    36
//
sl@0
    37
sl@0
    38
#define __E32TEST_EXTENSION__
sl@0
    39
#include <e32test.h>
sl@0
    40
#include <e32debug.h>
sl@0
    41
#include <e32base.h>
sl@0
    42
#include <e32base_private.h>
sl@0
    43
#include "mmudetect.h"
sl@0
    44
sl@0
    45
LOCAL_D RTest test(_L("T_IPCSAFETY"));
sl@0
    46
sl@0
    47
void GoodExitWithError();
sl@0
    48
sl@0
    49
TInt* DataToSplat;
sl@0
    50
RSemaphore BadSemaphore;
sl@0
    51
sl@0
    52
// Server stuff
sl@0
    53
sl@0
    54
_LIT(KBadServerName,"BadServer");
sl@0
    55
sl@0
    56
class CBadSession : public CSession2
sl@0
    57
	{
sl@0
    58
	virtual void ServiceL(const RMessage2& aMessage);
sl@0
    59
	};
sl@0
    60
sl@0
    61
class CBadServer : public CServer2
sl@0
    62
	{
sl@0
    63
public:
sl@0
    64
	CBadServer(CActive::TPriority aPriority) : CServer2(aPriority)
sl@0
    65
		{}
sl@0
    66
	virtual CBadSession* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
sl@0
    67
		{
sl@0
    68
		return new (ELeave) CBadSession();
sl@0
    69
		}
sl@0
    70
	};
sl@0
    71
sl@0
    72
void CBadSession::ServiceL(const RMessage2& aMessage)
sl@0
    73
	{
sl@0
    74
	TBuf16<1024> buf;
sl@0
    75
	DataToSplat = (TInt*)aMessage.Ptr1();
sl@0
    76
	BadSemaphore.Signal();
sl@0
    77
	// Read the buffer lots of times to widen the time window
sl@0
    78
	for (TInt i=0; i<1024; i++)
sl@0
    79
		aMessage.Read(0, buf, 0);
sl@0
    80
	CActiveScheduler::Stop();
sl@0
    81
	aMessage.Complete(KErrNone);
sl@0
    82
	}
sl@0
    83
sl@0
    84
TInt BadServerThread(TAny*)
sl@0
    85
	{
sl@0
    86
	CTrapCleanup* cleanup=CTrapCleanup::New();
sl@0
    87
	if (!cleanup)
sl@0
    88
		return KErrNoMemory;
sl@0
    89
	CActiveScheduler* scheduler = new CActiveScheduler();
sl@0
    90
	if (!scheduler)
sl@0
    91
		return KErrNoMemory;
sl@0
    92
	CActiveScheduler::Install(scheduler);
sl@0
    93
	CBadServer* server = new CBadServer(CActive::EPriorityStandard);
sl@0
    94
	if (!server)
sl@0
    95
		return KErrNoMemory;
sl@0
    96
	TInt r = server->Start(KBadServerName);
sl@0
    97
	if (r != KErrNone)
sl@0
    98
		return r;
sl@0
    99
	RThread::Rendezvous(KErrNone);
sl@0
   100
	CActiveScheduler::Start();
sl@0
   101
	delete server;
sl@0
   102
	delete scheduler;
sl@0
   103
	delete cleanup;
sl@0
   104
	return KErrNone;
sl@0
   105
	}
sl@0
   106
sl@0
   107
class RBadSession : public RSessionBase
sl@0
   108
	{
sl@0
   109
public:
sl@0
   110
	TInt Connect()
sl@0
   111
		{
sl@0
   112
		return CreateSession(KBadServerName, TVersion(0,0,0));
sl@0
   113
		}
sl@0
   114
	void AccessMe(TDesC* aBuf, TInt* aValue);
sl@0
   115
	};
sl@0
   116
sl@0
   117
void RBadSession::AccessMe(TDesC* aBuf, TInt* aValue)
sl@0
   118
	{
sl@0
   119
	SendReceive(0, TIpcArgs(aBuf, aValue));
sl@0
   120
	};
sl@0
   121
sl@0
   122
// Bad writer thread
sl@0
   123
sl@0
   124
TInt * const KAliasRegion = (TInt*)0x00200000;
sl@0
   125
const TUint KAliasMask = 0x000fffff;
sl@0
   126
sl@0
   127
void BadExceptionHandler(TExcType, TInt, TInt, TInt, TUint aStackArgument)
sl@0
   128
	{
sl@0
   129
	// just retry the instruction after a delay
sl@0
   130
	User::AfterHighRes(0);
sl@0
   131
	return;
sl@0
   132
	}
sl@0
   133
sl@0
   134
TInt BadWriterThread(TAny*)
sl@0
   135
	{
sl@0
   136
	// set the exception handler so that we don't die when touching the ipc region
sl@0
   137
	// as it won't be mapped until an unpredictable time
sl@0
   138
	User::SetExceptionHandler((TExceptionHandler)BadExceptionHandler, KExceptionFault);
sl@0
   139
	// wait for the server to tell us where to overwrite
sl@0
   140
	BadSemaphore.Wait();
sl@0
   141
sl@0
   142
	TInt* target = (TInt*)(((TUint)DataToSplat&KAliasMask)|(TUint)KAliasRegion);
sl@0
   143
	*target = KErrGeneral;
sl@0
   144
sl@0
   145
	return KErrNone;
sl@0
   146
	}
sl@0
   147
sl@0
   148
// The server process
sl@0
   149
sl@0
   150
TInt BadServerProcess()
sl@0
   151
	{
sl@0
   152
	test.Title();
sl@0
   153
	test.Start(_L("Test bad server overwriting good client memory"));
sl@0
   154
sl@0
   155
	BadSemaphore.CreateLocal(0);
sl@0
   156
sl@0
   157
	test.Next(_L("Setup bad server"));
sl@0
   158
	RThread serverThread;
sl@0
   159
	TRequestStatus serverStatus, serverRendezvous;
sl@0
   160
	test_KErrNone(serverThread.Create(_L("BadServer"), BadServerThread, KDefaultStackSize, NULL, NULL));
sl@0
   161
	serverThread.Logon(serverStatus);
sl@0
   162
	serverThread.Rendezvous(serverRendezvous);
sl@0
   163
	serverThread.Resume();
sl@0
   164
	User::WaitForRequest(serverRendezvous);
sl@0
   165
sl@0
   166
	test.Next(_L("Start bad writer thread"));
sl@0
   167
	RThread writerThread;
sl@0
   168
	TRequestStatus writerStatus;
sl@0
   169
	test_KErrNone(writerThread.Create(_L("BadWriter"), BadWriterThread, KDefaultStackSize, NULL, NULL));
sl@0
   170
	writerThread.Logon(writerStatus);
sl@0
   171
	writerThread.SetPriority(EPriorityMore);
sl@0
   172
	writerThread.Resume();
sl@0
   173
sl@0
   174
	test.Next(_L("Run the good client"));
sl@0
   175
	RProcess goodProcess;
sl@0
   176
	TRequestStatus goodStatus;
sl@0
   177
	test_KErrNone(goodProcess.Create(_L("T_IPCSAFETY"), _L("client")));
sl@0
   178
	goodProcess.Logon(goodStatus);
sl@0
   179
	goodProcess.Resume();
sl@0
   180
sl@0
   181
	test.Next(_L("Wait for server to die"));
sl@0
   182
	User::WaitForRequest(serverStatus);
sl@0
   183
	test_Equal(EExitKill, serverThread.ExitType());
sl@0
   184
	test_KErrNone(serverThread.ExitReason());
sl@0
   185
sl@0
   186
	test.Next(_L("Check if client had memory overwritten"));
sl@0
   187
	User::WaitForRequest(goodStatus);
sl@0
   188
	test_Equal(EExitKill, goodProcess.ExitType());
sl@0
   189
	test_KErrNone(goodProcess.ExitReason());
sl@0
   190
sl@0
   191
	test.Next(_L("Kill off writer thread"));
sl@0
   192
	writerThread.Kill(KErrNone);
sl@0
   193
	User::WaitForRequest(writerStatus);
sl@0
   194
	test_Equal(EExitKill, writerThread.ExitType());
sl@0
   195
	test_KErrNone(writerThread.ExitReason());
sl@0
   196
sl@0
   197
	test.End();
sl@0
   198
	return KErrNone;
sl@0
   199
	}
sl@0
   200
sl@0
   201
// The client process
sl@0
   202
sl@0
   203
TInt GoodClientProcess()
sl@0
   204
	{
sl@0
   205
	RBadSession bad;
sl@0
   206
	TBuf16<1024> buf;
sl@0
   207
	TInt r = KErrNone;
sl@0
   208
	buf.SetLength(1024);
sl@0
   209
	// just keep trying to connect if the server isn't talkative yet
sl@0
   210
	while (bad.Connect() != KErrNone)
sl@0
   211
		User::After(1);
sl@0
   212
	bad.AccessMe(&buf, &r);
sl@0
   213
	// Returns r, which logically should be KErrNone as servers aren't
sl@0
   214
	// supposed to be able to modify
sl@0
   215
	return r;
sl@0
   216
	}
sl@0
   217
sl@0
   218
// Main
sl@0
   219
sl@0
   220
GLDEF_C TInt E32Main()
sl@0
   221
    {
sl@0
   222
	TBuf16<512> cmd;
sl@0
   223
	User::CommandLine(cmd);
sl@0
   224
sl@0
   225
	// this test hardcodes various multiple memory model parameters
sl@0
   226
	// and the moving model's aliasing technique is not susceptible to
sl@0
   227
	// the problem in the first place
sl@0
   228
	TUint32 memmodel = MemModelAttributes();
sl@0
   229
	if ((memmodel & EMemModelTypeMask) != EMemModelTypeMultiple)
sl@0
   230
		return KErrNone;
sl@0
   231
sl@0
   232
	if(cmd.Length())
sl@0
   233
		return GoodClientProcess();
sl@0
   234
	else
sl@0
   235
		return BadServerProcess();
sl@0
   236
    }
sl@0
   237