diff -r 000000000000 -r a41df078684a kerneltest/e32test/system/t_prot.cpp --- /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 +#include "u32std.h" +#include +#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); + } +