--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/system/t_prot.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,539 @@
+// Copyright (c) 1996-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:
+// e32test\system\t_prot.cpp
+// Overview:
+// Tests that the kernel panics the user rather than dying in
+// various situations
+// API Information:
+// N/A
+// Details:
+// - Verify that printing a long string does not panic.
+// - Verify that a stack overflow in a thread causes a panic.
+// - Create the thread which panics a dead thread, verify that
+// it isn't panicked for doing this.
+// - Create the thread which panics a bad handle, verify that
+// it isn't panicked for doing this.
+// - Verify that an RSession send from an uninitialised handle
+// causes a panic.
+// - Verify that the thread causing an exception, for a variety
+// of reasons, is panicked.
+// - Verify thread writing to kernel data is panicked.
+// - Verify that RAM disk access either causes a panic or is
+// denied, based on the platform security settings.
+// - Verify that an RThread::RequestComplete() with an invalid
+// address causes a panic. Verify results are as expected.
+// Platforms/Drives/Compatibility:
+// All.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+//
+//
+
+#include <e32test.h>
+#include "u32std.h"
+#include <e32panic.h>
+#include "../mmu/mmudetect.h"
+
+void DoUndefinedInstruction();
+
+const TInt KHeapSize=0x200;
+const TInt KThreadReturnValue=9999;
+
+_LIT(KLitKernExec,"KERN-EXEC");
+
+class RSessionTest : public RSessionBase
+ {
+public:
+ void DoSend();
+ };
+
+
+void RSessionTest::DoSend()
+ {
+ Send(34,TIpcArgs(78));
+ //Send(34,(TAny*)78);
+ };
+
+LOCAL_D RTest test(_L("T_PROT"));
+LOCAL_D RTest t(_L("T_PROT thread"));
+
+enum TAction
+ {
+ EDataAbort=0,
+ EPrefetchAbort=1,
+ EUndefinedInstruction=2,
+ };
+
+typedef void (*PFV)(void);
+
+#ifndef __MARM__
+void DoUndefinedInstruction()
+ {
+#ifdef __GCC32__
+ asm("int 6");
+#else
+ _asm int 6;
+#endif
+ }
+#endif
+
+LOCAL_C TInt ExceptionThread(TAny* anAction)
+ {
+ TAction action=(TAction)((TInt) anAction);
+ switch (action)
+ {
+ case EDataAbort:
+ *(TInt*)0=0;
+ break;
+ case EPrefetchAbort:
+ {
+// PFV f=(PFV)NULL;
+ PFV f=(PFV)0x80000; // don't use NULL since it is readable on Snowdrop
+ (*f)();
+ break;
+ }
+ case EUndefinedInstruction:
+ DoUndefinedInstruction();
+ break;
+ };
+ return 0;
+ }
+
+LOCAL_C void RunTestThread(TAction anAction)
+ {
+ RThread t;
+ TInt r=t.Create(_L("TestThread"),ExceptionThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)anAction);
+ test(r==KErrNone);
+ TRequestStatus s;
+ t.Logon(s);
+ test(s==KRequestPending);
+ t.Resume();
+ User::WaitForRequest(s);
+ test(t.ExitType()==EExitPanic);
+ test(t.ExitCategory()==_L("KERN-EXEC"));
+ test(t.ExitReason()==ECausedException);
+ CLOSE_AND_WAIT(t);
+ }
+
+LOCAL_C TInt UnintThread(TAny* )
+ {
+
+ RSessionTest rsb;
+ rsb.DoSend();
+ FOREVER
+ ;
+ }
+
+void testSession()
+//
+// Test 1
+//
+ {
+
+ RThread thread;
+ TRequestStatus stat;
+
+ test.Next(_L("Create UnintThread"));
+ TInt r=thread.Create(_L("UnintThread"),UnintThread,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume UnintThread"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check UnintThread panicked"));
+ test(thread.ExitCategory()==_L("KERN-EXEC"));
+// test(thread.ExitReason()==EBadHandle);
+ test(thread.ExitType()==EExitPanic);
+ CLOSE_AND_WAIT(thread);
+ }
+
+TInt dummy(TAny*)
+ {
+ return(KErrNone);
+ }
+
+// Dennis - modified this to panic a dead thread rather than a bad handle
+TInt pdThread(TAny*)
+ {
+ RThread thread;
+ TRequestStatus stat;
+ TInt r=thread.Create(_L("dummy"),dummy,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test(thread.ExitType()==EExitKill);
+ test(stat.Int()==KErrNone);
+ thread.Panic(_L("MYPANIC"),0x666); // this shouldn't panic pdThread
+ test(thread.ExitType()==EExitKill);
+ test(thread.ExitReason()==KErrNone);
+ CLOSE_AND_WAIT(thread);
+ return(KErrNone);
+ }
+
+void testPanicDeadThread()
+//
+// Dennis - modified this to panic a dead thread rather than a bad handle
+// Create the thread which panics a dead thread /*bad handle*/
+// Check that it isn't panicked for doing this
+//
+ {
+ RThread thread;
+ TRequestStatus stat;
+ test.Next(_L("Create PanicDeadThread"));
+ TInt r=thread.Create(_L("PanicDeadThread"),pdThread,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume PanicDeadThread"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check PanicDeadThread did not panic"));
+ test(thread.ExitReason()==KErrNone);
+ test(thread.ExitType()==EExitKill);
+ test(thread.ExitCategory()==_L("Kill"));
+ CLOSE_AND_WAIT(thread);
+ }
+
+TInt doDeadThreadStuff(TAny*)
+ {
+ RThread thread;
+ TRequestStatus stat;
+ TInt r=thread.Create(_L("dummy2"),dummy,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ thread.Resume();
+ User::WaitForRequest(stat);
+
+ thread.SetPriority(EPriorityNormal);
+
+ CLOSE_AND_WAIT(thread);
+ return(KErrNone);
+ }
+
+void testDeadThread()
+//
+// Create the thread which panics a bad handle
+// Check that it isn't panicked for doing this
+//
+ {
+ RThread thread;
+ TRequestStatus stat;
+ test.Next(_L("Create doDeadThreadStuff"));
+ TInt r=thread.Create(_L("doDeadThreadStuff"),doDeadThreadStuff,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume doDeadThreadStuff"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check doDeadThreadStuff did not panic"));
+ test(thread.ExitReason()==KErrNone);
+ test(thread.ExitType()==EExitKill);
+ test(thread.ExitCategory()==_L("Kill"));
+ CLOSE_AND_WAIT(thread);
+ }
+
+TInt MinimalThread(TAny*)
+//
+// Minimal thread, used in test 5
+//
+ {
+ return(KErrNone);
+ }
+
+LOCAL_C TInt ExceptThread(TAny* )
+ {
+
+ TUint* nullPtr=0;
+ *nullPtr=0xdead; // BANG!!
+ return KErrNone;
+ }
+
+
+void testExcept()
+//
+// Test thread causing exception is panicked
+//
+ {
+
+ RThread thread;
+ TRequestStatus stat;
+
+ test.Next(_L("Create ExceptThread"));
+ TInt r=thread.Create(_L("ExceptThread"),ExceptThread,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume ExceptThread"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check ExceptThread panicked"));
+ test(thread.ExitCategory()==_L("KERN-EXEC"));
+ test(thread.ExitReason()==ECausedException);
+ test(thread.ExitType()==EExitPanic);
+ CLOSE_AND_WAIT(thread);
+ }
+
+LOCAL_C TInt StackThread(TAny* )
+ {
+
+ TFileName heresAnotherOne;
+ StackThread((TAny*)heresAnotherOne.Ptr()); // go recursive
+ return KErrNone;
+ }
+
+void testStackOverflow()
+//
+// Thread overflowing its stack is panicked
+//
+ {
+
+ RThread thread;
+ TRequestStatus stat;
+
+ test.Next(_L("Create StackThread"));
+ TInt r=thread.Create(_L("StackThread"),StackThread,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume StackThread"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check StackThread panicked"));
+ test(thread.ExitCategory()==_L("KERN-EXEC"));
+ test(thread.ExitReason()==ECausedException);
+ test(thread.ExitType()==EExitPanic);
+ CLOSE_AND_WAIT(thread);
+ }
+
+LOCAL_C TInt KernWriter(TAny* )
+ {
+
+ TUint* kernPtr=(TUint*)KernData();
+ *kernPtr=0xdead; // BANG!!
+ return KErrNone;
+ }
+
+LOCAL_C TInt RamDiskWriter(TAny* )
+ {
+
+ TFindChunk fChunk(_L("*TheRamDriveChunk*"));
+ TFullName n;
+ TInt r=fChunk.Next(n);
+ RChunk ch;
+ r=ch.Open(fChunk);
+ if(r!=KErrNone)
+ return r;
+ TUint8* rdPtr=ch.Base();
+ *rdPtr=0xaa; // BANG!!
+ return KErrNone;
+ }
+
+
+void testKernelWriter()
+//
+// Thread writing to kernel data is panicked
+//
+ {
+
+ RThread thread;
+ TRequestStatus stat;
+
+ test.Next(_L("Create KernWriter"));
+ TInt r=thread.Create(_L("KernWriter"),KernWriter,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume KernWriter"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test.Next(_L("Check KernWriter panicked"));
+ test(thread.ExitCategory()==_L("KERN-EXEC"));
+ test(thread.ExitReason()==ECausedException);
+ test(thread.ExitType()==EExitPanic);
+ CLOSE_AND_WAIT(thread);
+ }
+
+void testRamDiskAccess()
+ {
+
+ RThread thread;
+ TRequestStatus stat;
+
+ test.Next(_L("Create RamDiskWriter"));
+ TInt r=thread.Create(_L("RamDiskWriter"),RamDiskWriter,KDefaultStackSize,KHeapSize,KHeapSize,0);
+ test(r==KErrNone);
+
+ thread.Logon(stat);
+ test(thread.ExitType()==EExitPending);
+ test.Next(_L("Resume RamDiskWriter"));
+ thread.Resume();
+ User::WaitForRequest(stat);
+ if((!PlatSec::ConfigSetting(PlatSec::EPlatSecProcessIsolation))||(!PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement)))
+ {
+ test.Next(_L("Check RamDiskWriter panicked"));
+ test(thread.ExitCategory()==_L("KERN-EXEC"));
+ test(thread.ExitReason()==ECausedException);
+ test(thread.ExitType()==EExitPanic);
+ }
+ else
+ {
+ test.Next(_L("Check RamDiskWriter was refused access"));
+ test(thread.ExitReason()==KErrPermissionDenied);
+ test(thread.ExitType()==EExitKill);
+ }
+ CLOSE_AND_WAIT(thread);
+ }
+
+RThread MainThread;
+
+TInt RequestCompleteThread(TAny* aPtr)
+ {
+ TRequestStatus** pS=(TRequestStatus**)aPtr;
+ MainThread.RequestComplete(*pS,123);
+ return 0;
+ }
+
+_LIT(KReqCompThreadName,"ReqCompThread");
+void StartRequestCompleteThread(RThread& aThread, TRequestStatus** aStatus)
+ {
+ TInt r=aThread.Create(KReqCompThreadName,RequestCompleteThread,0x1000,0x1000,0x10000,aStatus);
+ test (r==KErrNone);
+ aThread.SetPriority(EPriorityMore);
+ TRequestStatus s;
+ aThread.Logon(s);
+ aThread.Resume();
+ User::WaitForRequest(s);
+ }
+
+_LIT(KLitUserCBase,"E32USER-CBase");
+GLDEF_C TInt E32Main()
+//
+// Main
+//
+ {
+
+ // don't want just in time debugging as we trap panics
+ TBool justInTime=User::JustInTime();
+ User::SetJustInTime(EFalse);
+
+ test.Title();
+ test.Start(_L("Test protection & panicking"));
+
+#if defined(__EPOC32__)
+ // this next test doesn't work under WINS because the string needs to be converted
+ // from UNICODE to ascii for printing to STDOUT, and that requires the string to be
+ // zero-terminated which panics because the string is too long.
+ test.Next(_L("Printing long string doesn't get me shot"));
+ test.Printf(_L("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
+ test.Printf(_L("\n"));
+#endif
+
+ if (HaveVirtMem())
+ {
+ test.Next(_L("Stack overflow shoots the thread not the kernel"));
+ testStackOverflow();
+ }
+
+ test.Next(_L("Panicking a closed thread doesn't panic the panicker!!"));
+ testPanicDeadThread();
+
+ test.Next(_L("Dead thread tests"));
+ testDeadThread();
+
+ test.Next(_L("RSession send from uninitialised handle"));
+ testSession();
+
+ test.Next(_L("Thread causing exception is killed"));
+ if (HaveVirtMem())
+ {
+ testExcept();
+ RunTestThread(EDataAbort);
+ RunTestThread(EPrefetchAbort);
+ }
+#ifndef __WINS__
+ RunTestThread(EUndefinedInstruction);
+#endif
+
+#if defined(__EPOC32__)
+ if (HaveDirectKernProt())
+ {
+ test.Next(_L("Thread writing to kernel data is killed"));
+ testKernelWriter();
+ }
+
+ if (HaveProcessProt())
+ {
+ test.Next(_L("Check access to RamDisk is denied"));
+ testRamDiskAccess();
+ }
+
+ if (HaveMMU())
+ {
+ test.Next(_L("RequestComplete() with bad address"));
+ TInt rqc=RThread().RequestCount();
+ test(MainThread.Duplicate(RThread())==KErrNone);
+ RThread t;
+ TRequestStatus s=KRequestPending;
+ TRequestStatus* pS=&s;
+ StartRequestCompleteThread(t,&pS);
+ test(t.ExitType()==EExitKill);
+ test(t.ExitReason()==KErrNone);
+ CLOSE_AND_WAIT(t);
+ test(s==123);
+ test(pS==NULL);
+ test(RThread().RequestCount()==rqc+1);
+ TRequestStatus** bad=(TRequestStatus**)0x80000000; // kernel space
+ StartRequestCompleteThread(t,bad);
+ test(t.ExitType()==EExitPanic);
+ test(t.ExitReason()==ECausedException);
+ test(t.ExitCategory()==KLitKernExec);
+ CLOSE_AND_WAIT(t);
+ test(RThread().RequestCount()==rqc+1);
+ pS=(TRequestStatus*)0x80000000;
+ StartRequestCompleteThread(t,&pS);
+ // Request status poked user side, so we expect a KERN-EXEC 3...
+ test(t.ExitType()==EExitPanic);
+ test(t.ExitReason()==ECausedException);
+ test(t.ExitCategory()==KLitKernExec);
+ CLOSE_AND_WAIT(t);
+ test(pS==NULL);
+ test(RThread().RequestCount()==rqc+1);
+ pS=(TRequestStatus*)(((TUint8*)&s)+0x80000); // aligned, within chunk max size but invalid
+ StartRequestCompleteThread(t,&pS);
+ // Request status poked user side, so we expect a KERN-EXEC 3...
+ test(t.ExitType()==EExitPanic);
+ test(t.ExitReason()==ECausedException);
+ test(t.ExitCategory()==KLitKernExec);
+ CLOSE_AND_WAIT(t);
+ test(pS==NULL);
+ test(RThread().RequestCount()==rqc+1);
+ }
+#endif
+
+ test.End();
+
+ User::SetJustInTime(justInTime);
+ return(KErrNone);
+ }
+