Update contrib.
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\secure\t_ipcsafety.cpp
16 // Test if it's possible for a thread in a server process to access the IPC alias
17 // region outside the control of the kernel.
21 // - Create a server which will take a long time IPCing any client request.
22 // - Create a high priority thread which will attempt to write to a given
23 // location in the IPC region, with an exception handler to retry if it fails.
24 // - Create a client process which connects to the server and offers a
25 // stack-based descriptor for IPC, as well as the address of another stack
26 // variable that should not be able to be accessed.
27 // - The bad writer will attempt to jump in and overwrite the variable,
28 // causing the client to return a detectable error.
29 // - Verify that this does not happen.
30 // Platforms/Drives/Compatibility:
31 // ARM with multiple memory model only.
32 // Assumptions/Requirement/Pre-requisites:
33 // Failures and causes:
34 // Base Port information:
38 #define __E32TEST_EXTENSION__
42 #include <e32base_private.h>
43 #include "mmudetect.h"
45 LOCAL_D RTest test(_L("T_IPCSAFETY"));
47 void GoodExitWithError();
50 RSemaphore BadSemaphore;
54 _LIT(KBadServerName,"BadServer");
56 class CBadSession : public CSession2
58 virtual void ServiceL(const RMessage2& aMessage);
61 class CBadServer : public CServer2
64 CBadServer(CActive::TPriority aPriority) : CServer2(aPriority)
66 virtual CBadSession* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
68 return new (ELeave) CBadSession();
72 void CBadSession::ServiceL(const RMessage2& aMessage)
75 DataToSplat = (TInt*)aMessage.Ptr1();
76 BadSemaphore.Signal();
77 // Read the buffer lots of times to widen the time window
78 for (TInt i=0; i<1024; i++)
79 aMessage.Read(0, buf, 0);
80 CActiveScheduler::Stop();
81 aMessage.Complete(KErrNone);
84 TInt BadServerThread(TAny*)
86 CTrapCleanup* cleanup=CTrapCleanup::New();
89 CActiveScheduler* scheduler = new CActiveScheduler();
92 CActiveScheduler::Install(scheduler);
93 CBadServer* server = new CBadServer(CActive::EPriorityStandard);
96 TInt r = server->Start(KBadServerName);
99 RThread::Rendezvous(KErrNone);
100 CActiveScheduler::Start();
107 class RBadSession : public RSessionBase
112 return CreateSession(KBadServerName, TVersion(0,0,0));
114 void AccessMe(TDesC* aBuf, TInt* aValue);
117 void RBadSession::AccessMe(TDesC* aBuf, TInt* aValue)
119 SendReceive(0, TIpcArgs(aBuf, aValue));
124 TInt * const KAliasRegion = (TInt*)0x00200000;
125 const TUint KAliasMask = 0x000fffff;
127 void BadExceptionHandler(TExcType, TInt, TInt, TInt, TUint aStackArgument)
129 // just retry the instruction after a delay
130 User::AfterHighRes(0);
134 TInt BadWriterThread(TAny*)
136 // set the exception handler so that we don't die when touching the ipc region
137 // as it won't be mapped until an unpredictable time
138 User::SetExceptionHandler((TExceptionHandler)BadExceptionHandler, KExceptionFault);
139 // wait for the server to tell us where to overwrite
142 TInt* target = (TInt*)(((TUint)DataToSplat&KAliasMask)|(TUint)KAliasRegion);
143 *target = KErrGeneral;
148 // The server process
150 TInt BadServerProcess()
153 test.Start(_L("Test bad server overwriting good client memory"));
155 BadSemaphore.CreateLocal(0);
157 test.Next(_L("Setup bad server"));
158 RThread serverThread;
159 TRequestStatus serverStatus, serverRendezvous;
160 test_KErrNone(serverThread.Create(_L("BadServer"), BadServerThread, KDefaultStackSize, NULL, NULL));
161 serverThread.Logon(serverStatus);
162 serverThread.Rendezvous(serverRendezvous);
163 serverThread.Resume();
164 User::WaitForRequest(serverRendezvous);
166 test.Next(_L("Start bad writer thread"));
167 RThread writerThread;
168 TRequestStatus writerStatus;
169 test_KErrNone(writerThread.Create(_L("BadWriter"), BadWriterThread, KDefaultStackSize, NULL, NULL));
170 writerThread.Logon(writerStatus);
171 writerThread.SetPriority(EPriorityMore);
172 writerThread.Resume();
174 test.Next(_L("Run the good client"));
175 RProcess goodProcess;
176 TRequestStatus goodStatus;
177 test_KErrNone(goodProcess.Create(_L("T_IPCSAFETY"), _L("client")));
178 goodProcess.Logon(goodStatus);
179 goodProcess.Resume();
181 test.Next(_L("Wait for server to die"));
182 User::WaitForRequest(serverStatus);
183 test_Equal(EExitKill, serverThread.ExitType());
184 test_KErrNone(serverThread.ExitReason());
186 test.Next(_L("Check if client had memory overwritten"));
187 User::WaitForRequest(goodStatus);
188 test_Equal(EExitKill, goodProcess.ExitType());
189 test_KErrNone(goodProcess.ExitReason());
191 test.Next(_L("Kill off writer thread"));
192 writerThread.Kill(KErrNone);
193 User::WaitForRequest(writerStatus);
194 test_Equal(EExitKill, writerThread.ExitType());
195 test_KErrNone(writerThread.ExitReason());
201 // The client process
203 TInt GoodClientProcess()
209 // just keep trying to connect if the server isn't talkative yet
210 while (bad.Connect() != KErrNone)
212 bad.AccessMe(&buf, &r);
213 // Returns r, which logically should be KErrNone as servers aren't
214 // supposed to be able to modify
220 GLDEF_C TInt E32Main()
223 User::CommandLine(cmd);
225 // this test hardcodes various multiple memory model parameters
226 // and the moving model's aliasing technique is not susceptible to
227 // the problem in the first place
228 TUint32 memmodel = MemModelAttributes();
229 if ((memmodel & EMemModelTypeMask) != EMemModelTypeMultiple)
233 return GoodClientProcess();
235 return BadServerProcess();