--- a/kerneltest/e32test/mmu/t_chunk.cpp Mon Dec 21 16:14:42 2009 +0000
+++ b/kerneltest/e32test/mmu/t_chunk.cpp Wed Dec 23 11:43:31 2009 +0000
@@ -37,6 +37,7 @@
// changes in out of memory status. Verify adjusting an RChunk generates
// the expected notifications.
// - Test finding a global chunk by name and verify results are as expected.
+// - Check read-only global chunks cannot be written to by other processes.
// Platforms/Drives/Compatibility:
// All.
// Assumptions/Requirement/Pre-requisites:
@@ -1149,17 +1150,193 @@
}
-/**Returns true if 'extended' is found in the command line*/
-TBool GetExtended()
+/**Returns true if argument is found in the command line*/
+TBool IsInCommandLine(const TDesC& aArg)
{
- _LIT(KExtended,"extended");
TBuf<64> c;
User::CommandLine(c);
- if (c.FindF(KExtended) >= 0)
+ if (c.FindF(aArg) >= 0)
return ETrue;
return EFalse;
}
+_LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
+_LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
+_LIT(KTestParamRo, "restro");
+_LIT(KTestParamRw, "restrw");
+_LIT(KTestParamWait, "restwait");
+_LIT(KTestParamWritableChunk, "restwritable");
+
+enum TTestProcessParameters
+ {
+ ETestRw = 0x1,
+ ETestWait = 0x2,
+ ETestWritableChunk = 0x4,
+ };
+
+void TestReadOnlyProcess(TUint aParams)
+ {
+ TInt r;
+ RChunk chunk;
+ RSemaphore sem;
+
+ test.Start(_L("Open global chunk"));
+ r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
+ test_KErrNone(r);
+
+ test(chunk.IsReadable());
+ r = chunk.Adjust(1);
+ if (aParams & ETestWritableChunk)
+ {
+ test(chunk.IsWritable());
+ test_KErrNone(r);
+ }
+ else
+ {
+ test(!chunk.IsWritable());
+ test_Equal(KErrAccessDenied, r);
+ }
+
+ if (aParams & ETestWait)
+ {
+ RProcess::Rendezvous(KErrNone);
+ test.Next(_L("Wait on semaphore"));
+ r = sem.OpenGlobal(KTestSemaphoreReadOnly);
+ test_KErrNone(r);
+ sem.Wait();
+ }
+
+ test.Next(_L("Read"));
+ TUint8 read = *(volatile TUint8*) chunk.Base();
+ (void) read;
+
+ if (aParams & ETestRw)
+ {
+ test.Next(_L("Write"));
+ TUint8* write = chunk.Base();
+ *write = 0x3d;
+ }
+
+ chunk.Close();
+ if (aParams & ETestWait)
+ {
+ sem.Close();
+ }
+ test.End();
+ }
+
+void TestReadOnly()
+ {
+ TInt r;
+ RChunk chunk;
+ RProcess process1;
+ RProcess process2;
+ RSemaphore sem;
+ TRequestStatus rs;
+ TRequestStatus rv;
+
+ // Assumption is made that any memory model from Flexible onwards that supports
+ // read-only memory also supports read-only chunks
+ if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
+ {
+ test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
+ return;
+ }
+
+ TBool jit = User::JustInTime();
+ User::SetJustInTime(EFalse);
+
+ test.Start(_L("Create writable global chunk"));
+ TChunkCreateInfo info;
+ info.SetNormal(0, 1234567);
+ info.SetGlobal(KTestChunkReadOnly);
+ r = chunk.Create(info);
+ test_KErrNone(r);
+ test(chunk.IsReadable());
+ test(chunk.IsWritable());
+
+ test.Next(_L("Adjust size"));
+ r = chunk.Adjust(1); // add one page
+ test_KErrNone(r);
+
+ test.Next(_L("Attempt read/write 1"));
+ r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
+ test_KErrNone(r);
+ process1.Logon(rs);
+ process1.Resume();
+ User::WaitForRequest(rs);
+ test_Equal(EExitKill, process1.ExitType());
+ test_KErrNone(process1.ExitReason());
+ CLOSE_AND_WAIT(process1);
+ CLOSE_AND_WAIT(chunk);
+
+ test.Next(_L("Create read-only global chunk"));
+ info.SetReadOnly();
+ r = chunk.Create(info);
+ test_KErrNone(r);
+ test(chunk.IsReadable());
+ test(chunk.IsWritable());
+ // To keep in sync with the 'process2' process
+ r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
+ test_KErrNone(r);
+
+ test.Next(_L("Attempt read 1"));
+ r = process1.Create(RProcess().FileName(), KTestParamRo);
+ test_KErrNone(r);
+ process1.Logon(rs);
+ process1.Resume();
+ User::WaitForRequest(rs);
+ test_Equal(EExitPanic, process1.ExitType());
+ test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
+ CLOSE_AND_WAIT(process1);
+ // Create second process before commiting memory and make it wait
+ r = process2.Create(RProcess().FileName(), KTestParamWait);
+ test_KErrNone(r)
+ process2.Rendezvous(rv);
+ process2.Resume();
+ User::WaitForRequest(rv);
+
+ test.Next(_L("Adjust size"));
+ r = chunk.Adjust(1); // add one page
+ test_KErrNone(r);
+
+ test.Next(_L("Attempt read 2"));
+ r = process1.Create(RProcess().FileName(), KTestParamRo);
+ test_KErrNone(r);
+ process1.Logon(rs);
+ process1.Resume();
+ User::WaitForRequest(rs);
+ test_Equal(EExitKill, process1.ExitType());
+ test_KErrNone(process1.ExitReason());
+ CLOSE_AND_WAIT(process1);
+
+ test.Next(_L("Attempt read/write 1"));
+ r = process1.Create(RProcess().FileName(), KTestParamRw);
+ test_KErrNone(r);
+ process1.Logon(rs);
+ process1.Resume();
+ User::WaitForRequest(rs);
+ test_Equal(EExitPanic, process1.ExitType());
+ test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
+ CLOSE_AND_WAIT(process1);
+ // Controlling process is not affected
+ TUint8* write = chunk.Base();
+ *write = 0x77;
+
+ test.Next(_L("Attempt read/write 2"));
+ test_Equal(EExitPending, process2.ExitType());
+ process2.Logon(rs);
+ sem.Signal();
+ User::WaitForRequest(rs);
+ test_Equal(EExitPanic, process2.ExitType());
+ test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
+ CLOSE_AND_WAIT(process2);
+
+ chunk.Close();
+ sem.Close();
+ test.End();
+ User::SetJustInTime(jit);
+ }
TInt E32Main()
//
@@ -1180,15 +1357,38 @@
test(l.CancelLazyDllUnload()==KErrNone);
l.Close();
- __KHEAP_MARK;
+ _LIT(KExtended,"extended");
- if (GetExtended() )
+ if (IsInCommandLine(KExtended))
+ {
+ __KHEAP_MARK;
+ test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
+ TestFullAddressSpace(ETrue);
+ __KHEAP_MARKEND;
+ }
+ else if (IsInCommandLine(KTestParamRo))
{
- test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
- TestFullAddressSpace(ETrue);
- }
+ test_KErrNone(User::RenameProcess(KTestParamRo));
+ TestReadOnlyProcess(0);
+ }
+ else if (IsInCommandLine(KTestParamRw))
+ {
+ test_KErrNone(User::RenameProcess(KTestParamRw));
+ TestReadOnlyProcess(ETestRw);
+ }
+ else if (IsInCommandLine(KTestParamWait))
+ {
+ test_KErrNone(User::RenameProcess(KTestParamWait));
+ TestReadOnlyProcess(ETestRw | ETestWait);
+ }
+ else if (IsInCommandLine(KTestParamWritableChunk))
+ {
+ test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
+ TestReadOnlyProcess(ETestWritableChunk | ETestRw);
+ }
else
{
+ __KHEAP_MARK;
test.Start(_L("Testing.."));
testAdjustChunk();
test.Next(_L("Test1"));
@@ -1223,12 +1423,12 @@
test.Next(_L("Test for race conditions in chunk closure"));
TestClosure();
+ test.Next(_L("Read-only chunks"));
+ TestReadOnly();
test.End();
- }
+ __KHEAP_MARKEND;
+ }
test.Close();
- __KHEAP_MARKEND;
-
-
return(KErrNone);
}