author | William Roberts <williamr@symbian.org> |
Mon, 28 Jun 2010 11:25:30 +0100 | |
branch | GCC_SURGE |
changeset 184 | 0e2270015475 |
parent 109 | b3a1d9898418 |
permissions | -rw-r--r-- |
// Copyright (c) 2002-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\secure\t_sdrivers.cpp // Overview: // Test the security aspects of device drivers. // API Information: // N/A // Details: // - For a variety of capability sets, test loading and opening various // devices and check that the results are as expected. // Platforms/Drives/Compatibility: // All. // Assumptions/Requirement/Pre-requisites: // Failures and causes: // Base Port information: // // #define __INCLUDE_CAPABILITY_NAMES__ #define __E32TEST_EXTENSION__ #include <e32test.h> #include <e32svr.h> // SYM_BRANCH: Delete old sound driver // #include <mdasound.h> #include <d32comm.h> #include <d32usbc.h> #include <d32ethernet.h> LOCAL_D RTest test(_L("T_SDRIVERS")); TCapabilitySet Capabilities; LOCAL_C TBool CheckLoaded(TInt aResult) { switch(aResult) { case KErrAlreadyExists: RDebug::Print(_L(" Already Exists")); return ETrue; case KErrNone: RDebug::Print(_L(" No Error")); return ETrue; case KErrNotFound: RDebug::Print(_L(" Not found")); return EFalse; default: test(EFalse); return EFalse; } } class TDriverCheck; typedef void (*TDriverCheckTestFunction)(TDriverCheck&); class TDriverCheck { public: TBool Check(TInt aResult); void ShowResult(); public: TDriverCheckTestFunction iTestFunction; const char* iDeviceName; TCapability iCapability; TBool iTested; TBool iPolicingVerified; }; TBool TDriverCheck::Check(TInt aResult) { switch(aResult) { case KErrNotSupported: RDebug::Print(_L(" Not Supported")); return ETrue; case KErrInUse: RDebug::Print(_L(" In Use")); return ETrue; case KErrAccessDenied: RDebug::Print(_L(" Access Denied (In Use?)")); return ETrue; case KErrNone: RDebug::Print(_L(" No Error")); break; case KErrPermissionDenied: RDebug::Print(_L(" Permission Denied")); break; default: RDebug::Print(_L(" Error %d"),aResult); return ETrue; } if(Capabilities.HasCapability(iCapability)) { if(aResult==KErrNone) iTested = 1; return aResult==KErrNone; } else if(PlatSec::IsCapabilityEnforced(iCapability)) { if(aResult==KErrPermissionDenied) iPolicingVerified = 1; return aResult==KErrPermissionDenied; } else { return aResult==KErrNone; } } void TDriverCheck::ShowResult() { TBuf8<32> nameBuf((const TUint8*)iDeviceName); TPtr name(nameBuf.Expand()); if(iTested) { if(iPolicingVerified) test.Printf(_L("* %S - Verified security checking\n"),&name); else test.Printf(_L("* %S - Did NOT verify security checking (Capabilties may be disabled)\n"),&name); } else test.Printf(_L("* %S - Not tested (Driver may be missing or in use)\n"),&name); } void TestELOCD(TDriverCheck& aCheck) { test.Next(_L("ELOCD")); test.Start(_L("Trying RLocalDrive with all local drives")); TInt i; TInt r; for(i=0; i<KMaxLocalDrives; i++) { RLocalDrive localDrive; TInt changedFlag = 0; r = localDrive.Connect(i,changedFlag); test(aCheck.Check(r)); localDrive.Close(); } test.End(); } #if defined (__WINS__) #define COMM_PDD_NAME _L("ECDRV.PDD") const TInt KMaxCommPdds=0; #else #define COMM_PDD_NAME _L("EUART") const TInt KMaxCommPdds=10; #endif void TestECOMM(TDriverCheck& aCheck) { test.Next(_L("ECOMM")); test.Start(_L("Load PDDs")); TInt i; TInt r; TBuf<10> pddName=COMM_PDD_NAME; for (i=-1; i<KMaxCommPdds; ++i) { if (i==0) pddName.Append(TChar('0')); else if (i>0) pddName[pddName.Length()-1] = (TText)('0'+i); r = User::LoadPhysicalDevice(pddName); CheckLoaded(r); } test.Next(_L("Load LDD")); r = User::LoadLogicalDevice(_L("ECOMM.LDD")); if(!CheckLoaded(r)) goto done; test.Next(_L("Open Channels")); for(i=0; i<10; i++) { RBusDevComm commDevice; r = commDevice.Open(i); test(aCheck.Check(r)); commDevice.Close(); } done: test.End(); } void TestEUSBC(TDriverCheck& aCheck) { test.Next(_L("EUSBC")); test.Start(_L("Load LDD")); TInt r = User::LoadLogicalDevice(_L("EUSBC.LDD")); if(!CheckLoaded(r)) goto done; test.Next(_L("Open Channel")); { RDevUsbcClient usbDevice; r = usbDevice.Open(0); test(aCheck.Check(r)); usbDevice.Close(); } done: test.End(); } void TestENET(TDriverCheck& aCheck) { test.Next(_L("ENET")); test.Start(_L("Load PDD")); TInt r = User::LoadPhysicalDevice(_L("ETHERNET.PDD")); if(!CheckLoaded(r)) goto done; test.Start(_L("Load LDD")); r = User::LoadLogicalDevice(_L("ENET.LDD")); if(!CheckLoaded(r)) goto done; test.Next(_L("Open Channel")); { RBusDevEthernet ethernetDevice; r = ethernetDevice.Open(0); test(aCheck.Check(r)); ethernetDevice.Close(); } done: test.End(); } // SYM_BRANCH: Delete old sound driver #if 0 void TestESOUND(TDriverCheck& aCheck) { test.Next(_L("ESOUND")); test.Start(_L("Load PDD")); TInt r = User::LoadPhysicalDevice(_L("ESDRV.PDD")); if(!CheckLoaded(r)) goto done; test.Next(_L("Load LDD")); r = User::LoadLogicalDevice(_L("ESOUND.LDD")); if(!CheckLoaded(r)) goto done; test.Next(_L("Open Channel")); { RMdaDevSound soundDevice; r = soundDevice.Open(); test(aCheck.Check(r)); soundDevice.Close(); } done: test.End(); } #endif TDriverCheck DriverList[] = { {TestELOCD,"ELOCD",ECapabilityTCB}, {TestECOMM,"ECOMM",ECapabilityCommDD}, {TestEUSBC,"EUSBC",ECapabilityCommDD}, {TestENET,"ENET",ECapabilityCommDD}, // SYM_BRANCH: Delete old sound driver // {TestESOUND,"ESOUND",ECapabilityMultimediaDD}, {0} }; LOCAL_C TInt DoTests() { TInt result=0; test.Start(_L("Testing all LDDs...")); TInt i=0; while(DriverList[i].iTestFunction) { (*DriverList[i].iTestFunction)(DriverList[i]); result |= DriverList[i].iTested<<(i*2); result |= DriverList[i].iPolicingVerified<<(i*2+1); ++i; } test.End(); return result^0x55555555; } enum TTestProcessFunctions { ETestProcessDoTests, }; #include "d_sldd.h" #include "u32std.h" RDevice TestDevice; TInt TestGetCapsThread(TAny* aDes) { RThread::Rendezvous(KErrNone); TestDevice.GetCaps(*(TDes8*)aDes); return KErrNone; } void TestGetCaps() { TUint memModelAttributes = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL); if((memModelAttributes&EMemModelAttrKernProt)==false) return; // no kernel protection to test // open test device... test.Start(_L("Open test driver")); RLddTest ldd; _LIT(KTestDeviceName,"D_SLDD"); TInt r = User::LoadLogicalDevice(KTestDeviceName); test(r == KErrNone || r == KErrAlreadyExists); r = TestDevice.Open(KTestDeviceName); test_KErrNone(r); r = ldd.OpenLocal(); test_KErrNone(r); // get address of some kernel data... TUint32* kernelPtr; TUint32 kernelData; ldd.KernelTestData(kernelPtr,kernelData); // check device GetCaps works... test.Next(_L("Check GetCaps")); _LIT8(KDummyTestData,"Dummy Test Data"); TBuf8<256> caps; caps.Copy(KDummyTestData); test(caps.Compare(KDummyTestData)==0); TestDevice.GetCaps(caps); test(caps.Compare(KDummyTestData)!=0); // get another thread to try and call device GetCaps to write to kernel data... test.Next(_L("Check GetCaps with bad descriptor")); TPtr8 badCaps((TUint8*)kernelPtr,sizeof(TUint32)); RThread thread; r = thread.Create(_L("TestGetCapsThread"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)&badCaps); test_KErrNone(r); TRequestStatus ls; thread.Logon(ls); TRequestStatus rs; thread.Rendezvous(rs); thread.Resume(); User::WaitForRequest(rs); test_KErrNone(rs.Int()); User::WaitForRequest(ls); test_Equal(EExitPanic,thread.ExitType()); thread.Close(); // check kernel data is unchanged... TUint32 kernelData2; ldd.KernelTestData(kernelPtr,kernelData2); test_Equal(kernelData,kernelData2); // get another thread to try and call device GetCaps with descriptor in kernel memory... test.Next(_L("Check GetCaps with bad descriptor 2")); r = thread.Create(_L("TestGetCapsThread2"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)kernelPtr); test_KErrNone(r); thread.Logon(ls); thread.Rendezvous(rs); thread.Resume(); User::WaitForRequest(rs); test_KErrNone(rs.Int()); User::WaitForRequest(ls); test_Equal(EExitPanic,thread.ExitType()); thread.Close(); // check kernel data is unchanged... ldd.KernelTestData(kernelPtr,kernelData2); test_Equal(kernelData,kernelData2); // cleanup... ldd.Close(); TestDevice.Close(); test.End(); } #include "testprocess.h" GLDEF_C TInt E32Main() { Capabilities = TSecurityInfo(RProcess()).iCaps; test.Title(); if(User::CommandLineLength()) { TBuf<128> message; __ASSERT_COMPILE(ECapability_Limit<64); message.AppendFormat(_L("Tests with capabilities %08x%08x"),((TUint32*)&Capabilities)[1],((TUint32*)&Capabilities)[0]); test.Start(message); TInt result = DoTests(); // Don't test.End() so we don't get lots of 'Success's in logs return(result); } test.Start(_L("Start")); test.Next(_L("Check driver GetCaps() vulnerability")); TestGetCaps(); TInt i; TInt c; for(c=0; c<ECapability_Limit; c++) { RTestProcess p; TRequestStatus s; TBuf<128> message; TCapabilitySet caps; caps.SetAllSupported(); if(!caps.HasCapability((TCapability)c)) continue; caps.RemoveCapability((TCapability)c); TBuf8<128> capNameBuf; capNameBuf.Copy((const TUint8*)CapabilityNames[c]); TPtr capName(capNameBuf.Expand()); message.AppendFormat(_L("Tests with all capabilities except %S"),&capName); test.Next(message); p.Create(*(TUint32*)&caps,ETestProcessDoTests); p.Logon(s); p.Resume(); User::WaitForRequest(s); test(p.ExitType()==EExitKill); TInt result=s.Int()^0x55555555; i=0; while(DriverList[i].iTestFunction) { if(result & (1<<(i*2))) DriverList[i].iTested = ETrue; if(result & (1<<(i*2+1))) DriverList[i].iPolicingVerified = ETrue; ++i; } test((result>>(i*2))==0); CLOSE_AND_WAIT(p); } // Show results requiring manual inspection _LIT(KSeperatorText,"----------------------------------------------------------------------------\n"); test.Printf(_L("\n")); test.Printf(_L("RESULTS\n")); test.Printf(KSeperatorText); i=0; while(DriverList[i].iTestFunction) { DriverList[i].ShowResult(); ++i; } test.Printf(KSeperatorText); // Wait for a while, or for a key press test.Printf(_L("Waiting a short while for key press...\n")); TRequestStatus keyStat; test.Console()->Read(keyStat); RTimer timer; test(timer.CreateLocal()==KErrNone); TRequestStatus timerStat; timer.After(timerStat,20*1000000); User::WaitForRequest(timerStat,keyStat); if(keyStat!=KRequestPending) (void)test.Console()->KeyCode(); timer.Cancel(); test.Console()->ReadCancel(); User::WaitForAnyRequest(); test.End(); return(0); }