kerneltest/e32test/system/t_prot.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /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);
+	}
+